{
  "generatedAt": "2026-10-07T05:26:47.908Z",
  "site": {
    "name": "禾君科技官网",
    "version": "",
    "packageName": "hejun-website",
    "stack": [
      {
        "name": "@nuxt/image",
        "version": "^1.11.0"
      },
      {
        "name": "@nuxt/kit",
        "version": "^4.5.2"
      },
      {
        "name": "@nuxt/ui",
        "version": "^3.2.0"
      },
      {
        "name": "@pinia/nuxt",
        "version": "^0.7.0"
      },
      {
        "name": "@prisma/client",
        "version": "^6.5.0"
      },
      {
        "name": "@vue/compiler-sfc",
        "version": "^3.5.43"
      },
      {
        "name": "bcryptjs",
        "version": "^2.4.3"
      },
      {
        "name": "esbuild",
        "version": "0.28.2"
      },
      {
        "name": "h3",
        "version": "^2.0.1-rc.32"
      },
      {
        "name": "ioredis",
        "version": "^5.4.2"
      },
      {
        "name": "nanotar",
        "version": "^0.3.0"
      },
      {
        "name": "nodemailer",
        "version": "^6.10.0"
      },
      {
        "name": "nuxt",
        "version": "^4.0.0"
      },
      {
        "name": "pinia",
        "version": "^4.0.3"
      },
      {
        "name": "vue",
        "version": "^3.5.13"
      },
      {
        "name": "zod",
        "version": "^3.24.2"
      }
    ],
    "devStack": [
      {
        "name": "@iconify-json/lucide",
        "version": "^1.2.140"
      },
      {
        "name": "@iconify-json/mdi",
        "version": "^1.2.3"
      },
      {
        "name": "@iconify-json/simple-icons",
        "version": "^1.2.99"
      },
      {
        "name": "@types/bcryptjs",
        "version": "^2.4.6"
      },
      {
        "name": "@types/nodemailer",
        "version": "^6.4.17"
      },
      {
        "name": "pinyin-pro",
        "version": "^3.29.4"
      },
      {
        "name": "prisma",
        "version": "^6.5.0"
      },
      {
        "name": "sharp",
        "version": "^0.35.4"
      },
      {
        "name": "tailwindcss",
        "version": "^4.1.0"
      },
      {
        "name": "tsx",
        "version": "^4.19.2"
      },
      {
        "name": "typescript",
        "version": "^5.7.0"
      },
      {
        "name": "vitest",
        "version": "^2.1.8"
      },
      {
        "name": "vue-tsc",
        "version": "^3.3.11"
      }
    ],
    "scripts": [
      {
        "name": "dev",
        "cmd": "nuxt dev"
      },
      {
        "name": "gate",
        "cmd": "node scripts/gate-compile.mjs"
      },
      {
        "name": "gate:types",
        "cmd": "node scripts/gate-typecheck.mjs"
      },
      {
        "name": "gate:auto-imports",
        "cmd": "tsx scripts/gate-auto-imports.ts"
      },
      {
        "name": "log:500",
        "cmd": "powershell -NoProfile -Command \"Select-String '\\[500\\]' .dev.log | Select-Object -Last 20\""
      },
      {
        "name": "prebuild",
        "cmd": "npm run gate && npm run gate:types && npm run gate:auto-imports && npm run engine:spec && node scripts/generate-dev-docs.mjs && node scripts/gen-search-pinyin.mjs"
      },
      {
        "name": "build",
        "cmd": "nuxt build"
      },
      {
        "name": "generate",
        "cmd": "nuxt generate"
      },
      {
        "name": "preview",
        "cmd": "nuxt preview"
      },
      {
        "name": "postinstall",
        "cmd": "prisma generate"
      },
      {
        "name": "db:push",
        "cmd": "prisma db push"
      },
      {
        "name": "db:pull",
        "cmd": "prisma db pull"
      },
      {
        "name": "db:studio",
        "cmd": "prisma studio"
      },
      {
        "name": "db:seed",
        "cmd": "tsx prisma/seed.ts"
      },
      {
        "name": "db:doctor",
        "cmd": "node scripts/check-migrations.cjs"
      },
      {
        "name": "og:build",
        "cmd": "node scripts/generate-og-image.mjs"
      },
      {
        "name": "docs:build",
        "cmd": "npm run engine:spec && node scripts/generate-dev-docs.mjs && npm run docs:guide"
      },
      {
        "name": "docs:guide",
        "cmd": "tsx scripts/generate-dev-guide.ts"
      },
      {
        "name": "api:diff",
        "cmd": "tsx scripts/api-changelog.ts diff"
      },
      {
        "name": "api:changelog",
        "cmd": "tsx scripts/api-changelog.ts write"
      },
      {
        "name": "engine",
        "cmd": "tsx scripts/engine.ts"
      },
      {
        "name": "engine:list",
        "cmd": "tsx scripts/engine.ts list"
      },
      {
        "name": "ci:validate",
        "cmd": "tsx scripts/engine.ts validate"
      },
      {
        "name": "engine:validate",
        "cmd": "tsx scripts/engine.ts validate"
      },
      {
        "name": "engine:spec",
        "cmd": "tsx scripts/engine.ts spec"
      },
      {
        "name": "engine:gc",
        "cmd": "tsx scripts/engine.ts gc"
      },
      {
        "name": "engine:new",
        "cmd": "tsx scripts/engine.ts new"
      },
      {
        "name": "engine:pack",
        "cmd": "tsx scripts/engine.ts pack"
      },
      {
        "name": "engine:publish",
        "cmd": "tsx scripts/engine-publish.ts"
      },
      {
        "name": "engine:keygen",
        "cmd": "tsx scripts/engine.ts keygen"
      },
      {
        "name": "engine:remove",
        "cmd": "tsx scripts/engine.ts remove"
      },
      {
        "name": "engine:schema",
        "cmd": "tsx scripts/engine.ts schema"
      },
      {
        "name": "engine:license",
        "cmd": "tsx scripts/engine.ts license"
      },
      {
        "name": "typecheck",
        "cmd": "nuxt typecheck"
      },
      {
        "name": "test",
        "cmd": "vitest run"
      },
      {
        "name": "audit",
        "cmd": "node scripts/site-audit.mjs"
      },
      {
        "name": "audit:full",
        "cmd": "node scripts/site-audit.mjs --with-static"
      }
    ],
    "engines": {
      "node": ">=20.0.0"
    }
  },
  "engine": {
    "version": "1.0.0",
    "hooks": [
      {
        "name": "app:ready",
        "when": "服务端进程启动、钩子注册完成后触发一次",
        "payload": "{ engineVersion }",
        "status": "live"
      },
      {
        "name": "lead:created",
        "when": "客户通过 /contact 提交需求、线索写入成功后",
        "payload": "{ lead: { id, name, contact, company, interestSlug }, source }",
        "status": "live"
      },
      {
        "name": "product:afterSave",
        "when": "后台新增或编辑系统产品成功后",
        "payload": "{ product: { id, slug, name, status }, mode: \"create\" | \"update\" }",
        "status": "live"
      },
      {
        "name": "content:changed",
        "when": "后台改动内容（产品 / FAQ / 页面内容 / 版本日志）后",
        "payload": "{ kind: \"product\" | \"faq\" | \"page\" | \"changelog\", paths: string[] }",
        "status": "live"
      }
    ],
    "manifestFields": [
      {
        "name": "$schema",
        "type": "string",
        "required": false,
        "description": "（给编辑器用）指向 engines/manifest.schema.json，如 \"../../manifest.schema.json\"；引擎会忽略它"
      },
      {
        "name": "id",
        "type": "string",
        "required": true,
        "description": "扩展 id。必须与包目录名一致（引擎会核对，不一致直接判为清单非法）",
        "constraint": "匹配 ^[a-z][a-z0-9-]{1,40}$"
      },
      {
        "name": "type",
        "type": "enum(theme | module | plugin)",
        "required": true,
        "description": "扩展类型。必须与所在目录一致：themes/ → theme，modules/ → module，plugins/ → plugin"
      },
      {
        "name": "name",
        "type": "string",
        "required": true,
        "description": "显示名称，出现在后台「引擎与扩展」列表与文档里（1–40 字）",
        "constraint": "1–40 字"
      },
      {
        "name": "version",
        "type": "string",
        "required": true,
        "description": "语义化版本，形如 1.0.0。它决定运行时产物目录（.engine-build/<id>@<version>/）",
        "constraint": "匹配 ^\\d+\\.\\d+\\.\\d+(-[a-z0-9.]+)?$"
      },
      {
        "name": "description",
        "type": "string",
        "required": true,
        "description": "一句话说明这个扩展解决什么问题（1–300 字）",
        "constraint": "1–300 字"
      },
      {
        "name": "author",
        "type": "string",
        "required": false,
        "description": "作者署名，会写进打包描述文件",
        "default": "\"\"",
        "constraint": "最多 60 字"
      },
      {
        "name": "license",
        "type": "string",
        "required": false,
        "description": "开源协议，默认 MIT",
        "default": "\"MIT\"",
        "constraint": "最多 40 字"
      },
      {
        "name": "homepage",
        "type": "string",
        "required": false,
        "description": "项目主页或仓库地址",
        "default": "\"\"",
        "constraint": "最多 300 字"
      },
      {
        "name": "activation",
        "type": "object",
        "required": false,
        "description": "授权声明（离线授权码）。**只有付费扩展需要**：required 为 true 时，站主必须贴进一张由你签发的授权码才能启用。免费扩展不要加这个字段 —— 加了就是白给自己加一道门。授权码用 npm run engine:license 签发",
        "default": "{}"
      },
      {
        "name": "compat",
        "type": "object",
        "required": false,
        "description": "兼容性声明",
        "default": "{}"
      },
      {
        "name": "requires",
        "type": "string[]",
        "required": false,
        "description": "依赖的其他扩展，写「类型/id」，可加版本范围（@>=1.2.0 / @^1.2.0 / @~1.2.0 / 多个用空格分隔）。依赖未启用、或版本不满足时本扩展会被判为不可用（不会半启动）；引擎会检测循环依赖",
        "default": "[]"
      },
      {
        "name": "hooks",
        "type": "string[]",
        "required": false,
        "description": "声明监听的扩展点。只有列在这里的钩子才会被注册；写未埋点的钩子会被拒绝",
        "default": "[]"
      },
      {
        "name": "entry",
        "type": "string",
        "required": false,
        "description": "入口组件名（不含 .vue）。包内只有一个组件时可省略，引擎会自动取那一个",
        "default": "\"\"",
        "constraint": "最多 60 字"
      },
      {
        "name": "regions",
        "type": "string[]",
        "required": false,
        "description": "自动注入区域，如 layout.top、home.after-systems。留空表示只支持被 <TemplateSection> 点名使用",
        "default": "[]"
      },
      {
        "name": "adminNav",
        "type": "object[]",
        "required": false,
        "description": "后台侧边栏追加项。与核心导航重复时保留核心项",
        "default": "[]"
      },
      {
        "name": "permissions",
        "type": "object[]",
        "required": false,
        "description": "扩展自带的权限点。声明后模块的后台接口无需改核心的 route-perms.ts",
        "default": "[]"
      },
      {
        "name": "settings",
        "type": "object[]",
        "required": false,
        "description": "可在后台配置的设置项",
        "default": "[]"
      },
      {
        "name": "blocks",
        "type": "object[]",
        "required": false,
        "description": "本扩展提供的页面区块类型。声明后：后台页面编辑器能选到它 ✓、前台由引擎按 component 解析渲染 ✓ —— 模块作者不需要改核心的 block-registry.ts",
        "default": "[]"
      },
      {
        "name": "builtin",
        "type": "boolean",
        "required": false,
        "description": "是否随源码交付的内置扩展。内置项默认启用且不允许卸载，只允许停用",
        "default": "false"
      }
    ],
    "settingFields": [
      {
        "name": "key",
        "type": "string",
        "required": true,
        "description": "设置键。必须与组件 props 同名才会被自动传入；只允许小写字母、数字、下划线",
        "constraint": "匹配 ^[a-z][a-z0-9_]{1,40}$"
      },
      {
        "name": "label",
        "type": "string",
        "required": true,
        "description": "后台表单里显示的标签（1–40 字）",
        "constraint": "1–40 字"
      },
      {
        "name": "type",
        "type": "enum(text | textarea | bool | number | url)",
        "required": false,
        "description": "表单控件类型，决定后台如何渲染这一项",
        "default": "\"text\""
      },
      {
        "name": "default",
        "type": "string",
        "required": false,
        "description": "默认值。清单里统一写字符串；引擎按 type 归一化成 boolean / number 后才下发给组件（bool 写 \"true\" / \"false\"）",
        "default": "\"\"",
        "constraint": "最多 2000 字"
      },
      {
        "name": "hint",
        "type": "string",
        "required": false,
        "description": "填写提示，显示在输入框下方",
        "default": "\"\"",
        "constraint": "最多 200 字"
      },
      {
        "name": "public",
        "type": "boolean",
        "required": false,
        "description": "是否允许前台 /api/engines 读到。放密钥或内部文案时保持 false",
        "default": "false"
      }
    ],
    "packages": [
      {
        "id": "hejun-default",
        "type": "theme",
        "dir": "engines/themes/hejun-default",
        "manifest": {
          "$schema": "../../manifest.schema.json",
          "id": "hejun-default",
          "type": "theme",
          "name": "禾君默认主题",
          "version": "1.0.0",
          "description": "本站现有的整套前台外观：首页、产品系统（列表/详情/版本日志）、FAQ、联系我们、二次开发、文档与隐私页，以及页头页脚与页面区块。作为可切换的主题包交付 —— 换主题即换整套外观。",
          "author": "禾君科技",
          "license": "MIT",
          "builtin": true
        },
        "files": {
          "components": 13,
          "pages": 10,
          "server": 0,
          "hooks": false,
          "schema": false
        }
      },
      {
        "id": "moderncommerce",
        "type": "theme",
        "dir": "engines/themes/moderncommerce",
        "manifest": {
          "$schema": "../../manifest.schema.json",
          "id": "moderncommerce",
          "type": "theme",
          "name": "Modern Commerce",
          "version": "1.0.0",
          "description": "第二套主题：由 HTML 模板 Moderncommerce 转换而来，含首页与 服务 / 案例 / 博客 / 团队 / 联系 / FAQ 共 13 个页面，自带完整样式与动效（jQuery + GSAP + Slick）。与「禾君默认主题」互斥，同时只能激活一个。",
          "author": "禾君科技",
          "license": "MIT",
          "homepage": "https://www.hejun1.com/docs#engines",
          "compat": {
            "engine": ">=1.0.0",
            "nuxt": ">=4.0.0"
          },
          "settings": [
            {
              "key": "topbar_enabled",
              "label": "显示顶部联系条",
              "type": "bool",
              "default": "true",
              "hint": "关闭后隐藏页头最上方的联系方式条",
              "public": true
            },
            {
              "key": "footer_note",
              "label": "页脚补充文案",
              "type": "text",
              "default": "",
              "hint": "显示在页脚简介下方；留空则不显示。可在「页面内容」里按页覆盖",
              "public": true
            }
          ],
          "builtin": true
        },
        "files": {
          "components": 0,
          "pages": 14,
          "server": 0,
          "hooks": false,
          "schema": false
        }
      },
      {
        "id": "announcement-bar",
        "type": "module",
        "dir": "engines/modules/announcement-bar",
        "manifest": {
          "id": "announcement-bar",
          "type": "module",
          "name": "顶部公告条",
          "version": "1.0.0",
          "description": "站点顶部可关闭的公告条：后台维护公告内容与生效时间，前台自动取「当前生效」的一条展示。包含自己的数据表、后台页面、公开接口与权限点，是模块引擎的完整示例。",
          "author": "禾君科技",
          "license": "MIT",
          "compat": {
            "engine": ">=1.0.0",
            "nuxt": ">=4.0.0"
          },
          "hooks": [],
          "regions": [
            "layout.top"
          ],
          "adminNav": [
            {
              "to": "/admin/announcements",
              "label": "公告条"
            }
          ],
          "builtin": false,
          "permissions": [
            {
              "key": "announcement:manage",
              "name": "公告条管理（新增 / 删除）",
              "routes": [
                "POST /api/admin/announcements",
                "DELETE /api/admin/announcements"
              ]
            }
          ],
          "settings": [
            {
              "key": "position",
              "label": "展示位置",
              "type": "text",
              "default": "top",
              "hint": "目前支持 top（页面顶部）",
              "public": true
            },
            {
              "key": "dismissible",
              "label": "允许访客关闭",
              "type": "bool",
              "default": "true",
              "hint": "关闭状态存在浏览器本地，不做服务端记录",
              "public": true
            }
          ]
        },
        "files": {
          "components": 1,
          "pages": 1,
          "server": 4,
          "hooks": false,
          "schema": true
        }
      },
      {
        "id": "changelog-center",
        "type": "module",
        "dir": "engines/modules/changelog-center",
        "manifest": {
          "id": "changelog-center",
          "type": "module",
          "name": "版本日志",
          "version": "1.0.0",
          "description": "按产品分组的版本日志：后台维护（新增 / 编辑 / 删除），公开接口 GET /api/products/{slug}/changelogs 供前台的产品更新记录页消费。表通过外键挂在产品表上，所以依赖「系统产品」模块。",
          "author": "禾君科技",
          "license": "MIT",
          "homepage": "https://www.hejun1.com/docs#engines",
          "compat": {
            "engine": ">=1.0.0",
            "nuxt": ">=4.0.0"
          },
          "requires": [
            "module/product-catalog@>=1.0.0"
          ],
          "hooks": [],
          "regions": [],
          "adminNav": [
            {
              "to": "/admin/changelogs",
              "label": "版本日志"
            }
          ],
          "builtin": true,
          "permissions": [
            {
              "key": "changelog:create",
              "name": "新增日志",
              "routes": [
                "POST /api/admin/changelogs"
              ]
            },
            {
              "key": "changelog:edit",
              "name": "编辑日志",
              "routes": [
                "PUT /api/admin/changelogs"
              ]
            },
            {
              "key": "changelog:delete",
              "name": "删除日志",
              "routes": [
                "DELETE /api/admin/changelogs"
              ]
            }
          ]
        },
        "files": {
          "components": 0,
          "pages": 1,
          "server": 5,
          "hooks": false,
          "schema": true
        }
      },
      {
        "id": "demo-accounts",
        "type": "module",
        "dir": "engines/modules/demo-accounts",
        "manifest": {
          "id": "demo-accounts",
          "type": "module",
          "name": "演示账号",
          "version": "1.0.0",
          "description": "给客户开的限时只读演示账号：后台按产品开通（写入 Redis 里的限时会话，到期自动失效），访客用临时口令换一个只读 Cookie 再进演示站。表通过外键挂在产品表上，所以依赖「系统产品」模块。",
          "author": "禾君科技",
          "license": "MIT",
          "homepage": "https://www.hejun1.com/docs#engines",
          "compat": {
            "engine": ">=1.0.0",
            "nuxt": ">=4.0.0"
          },
          "requires": [
            "module/product-catalog@>=1.0.0"
          ],
          "hooks": [],
          "regions": [],
          "adminNav": [
            {
              "to": "/admin/demo-accounts",
              "label": "演示账号"
            }
          ],
          "builtin": true,
          "permissions": [
            {
              "key": "demo:manage",
              "name": "演示账号管理",
              "routes": [
                "POST /api/admin/demo-accounts",
                "DELETE /api/admin/demo-accounts"
              ]
            }
          ]
        },
        "files": {
          "components": 0,
          "pages": 1,
          "server": 5,
          "hooks": false,
          "schema": true
        }
      },
      {
        "id": "faq-manager",
        "type": "module",
        "dir": "engines/modules/faq-manager",
        "manifest": {
          "id": "faq-manager",
          "type": "module",
          "name": "FAQ 管理",
          "version": "1.0.0",
          "description": "常见问题：后台维护（新增 / 编辑 / 排序 / 隐藏 / 回收站），公开接口 GET /api/faqs 供前台 FAQ 页与任意页面消费。自带数据表、后台页面与权限点，是「业务模块」的官方样板。",
          "author": "禾君科技",
          "license": "MIT",
          "homepage": "https://www.hejun1.com/docs#engines",
          "compat": {
            "engine": ">=1.0.0",
            "nuxt": ">=4.0.0"
          },
          "hooks": [],
          "regions": [],
          "adminNav": [
            {
              "to": "/admin/faqs",
              "label": "常见问题"
            }
          ],
          "builtin": true,
          "permissions": [
            {
              "key": "faq:create",
              "name": "新增 FAQ",
              "routes": [
                "POST /api/admin/faqs"
              ]
            },
            {
              "key": "faq:edit",
              "name": "编辑 FAQ",
              "routes": [
                "PUT /api/admin/faqs"
              ]
            },
            {
              "key": "faq:delete",
              "name": "删除 FAQ（进回收站）",
              "routes": [
                "DELETE /api/admin/faqs"
              ]
            },
            {
              "key": "faq:restore",
              "name": "恢复已删除 FAQ",
              "routes": [
                "POST /api/admin/faqs/*/restore"
              ]
            }
          ]
        },
        "files": {
          "components": 0,
          "pages": 1,
          "server": 6,
          "hooks": false,
          "schema": true
        }
      },
      {
        "id": "lead-inbox",
        "type": "module",
        "dir": "engines/modules/lead-inbox",
        "manifest": {
          "id": "lead-inbox",
          "type": "module",
          "name": "客户线索",
          "version": "1.0.0",
          "description": "访客留言的统一收件箱：前台表单写入（手机号 / 微信校验 + 通知 + lead:created 扩展点），后台可搜索、改状态、写跟进备注、进回收站、按状态导出 CSV。自带数据表、后台页面与权限点。",
          "author": "禾君科技",
          "license": "MIT",
          "homepage": "https://www.hejun1.com/docs#engines",
          "compat": {
            "engine": ">=1.0.0",
            "nuxt": ">=4.0.0"
          },
          "hooks": [],
          "regions": [],
          "adminNav": [
            {
              "to": "/admin/leads",
              "label": "客户线索"
            }
          ],
          "builtin": true,
          "permissions": [
            {
              "key": "lead:view",
              "name": "查看线索",
              "routes": []
            },
            {
              "key": "lead:edit",
              "name": "更新状态与备注",
              "routes": [
                "PUT /api/admin/leads"
              ]
            },
            {
              "key": "lead:delete",
              "name": "删除线索（进回收站）",
              "routes": [
                "DELETE /api/admin/leads"
              ]
            },
            {
              "key": "lead:restore",
              "name": "恢复已删除线索",
              "routes": [
                "POST /api/admin/leads/*/restore"
              ]
            },
            {
              "key": "lead:export",
              "name": "导出线索（CSV）",
              "routes": [
                "GET /api/admin/leads/export"
              ]
            }
          ]
        },
        "files": {
          "components": 0,
          "pages": 1,
          "server": 6,
          "hooks": false,
          "schema": true
        }
      },
      {
        "id": "product-catalog",
        "type": "module",
        "dir": "engines/modules/product-catalog",
        "manifest": {
          "id": "product-catalog",
          "type": "module",
          "name": "系统产品",
          "version": "1.0.0",
          "description": "自研业务系统的产品目录：后台维护产品（图集、卖点、交付方式、SEO）与分类标签，公开接口 GET /api/products 供前台系统页与留言表单消费。自带 products / tags 两张表、两个后台页与权限点 —— 官方模块里的「系统产品 / 版本日志 / 演示账号」三件套以它为基础。",
          "author": "禾君科技",
          "license": "MIT",
          "homepage": "https://www.hejun1.com/docs#engines",
          "compat": {
            "engine": ">=1.0.0",
            "nuxt": ">=4.0.0"
          },
          "hooks": [],
          "regions": [],
          "adminNav": [
            {
              "to": "/admin/products",
              "label": "系统产品"
            },
            {
              "to": "/admin/tags",
              "label": "标签"
            }
          ],
          "builtin": true,
          "permissions": [
            {
              "key": "product:view",
              "name": "查看产品",
              "routes": []
            },
            {
              "key": "product:create",
              "name": "新增产品",
              "routes": [
                "POST /api/admin/products"
              ]
            },
            {
              "key": "product:edit",
              "name": "编辑产品",
              "routes": [
                "PUT /api/admin/products"
              ]
            },
            {
              "key": "product:delete",
              "name": "删除产品（进回收站）",
              "routes": [
                "DELETE /api/admin/products"
              ]
            },
            {
              "key": "product:restore",
              "name": "恢复已删除产品",
              "routes": [
                "POST /api/admin/products/*/restore"
              ]
            },
            {
              "key": "tag:create",
              "name": "新增标签",
              "routes": [
                "POST /api/admin/tags"
              ]
            },
            {
              "key": "tag:edit",
              "name": "编辑标签",
              "routes": [
                "PUT /api/admin/tags"
              ]
            },
            {
              "key": "tag:delete",
              "name": "删除标签",
              "routes": [
                "DELETE /api/admin/tags"
              ]
            }
          ]
        },
        "files": {
          "components": 0,
          "pages": 2,
          "server": 12,
          "hooks": false,
          "schema": true
        }
      },
      {
        "id": "lead-dup-guard",
        "type": "plugin",
        "dir": "engines/plugins/lead-dup-guard",
        "manifest": {
          "id": "lead-dup-guard",
          "type": "plugin",
          "name": "线索重复提示",
          "version": "1.0.0",
          "description": "监听 lead:created，用同一联系方式在近 30 天内是否提交过需求，把「重复线索」写进操作日志，方便销售判断是不是同一波需求反复来问。",
          "author": "禾君科技",
          "license": "MIT",
          "compat": {
            "engine": ">=1.0.0",
            "nuxt": ">=4.0.0"
          },
          "hooks": [
            "lead:created"
          ],
          "regions": [],
          "adminNav": [],
          "builtin": false,
          "settings": [
            {
              "key": "window_days",
              "label": "重复判定窗口（天）",
              "type": "number",
              "default": "30",
              "hint": "同一联系方式在这个天数内再次提交即视为重复"
            },
            {
              "key": "log_only",
              "label": "只记日志不提示",
              "type": "bool",
              "default": "true",
              "hint": "开启后仅在操作日志里记录，不改动线索内容"
            }
          ]
        },
        "files": {
          "components": 0,
          "pages": 0,
          "server": 0,
          "hooks": true,
          "schema": false
        }
      }
    ]
  },
  "structure": [
    {
      "dir": "assets",
      "fileCount": 2
    },
    {
      "dir": "components",
      "fileCount": 46
    },
    {
      "dir": "composables",
      "fileCount": 19
    },
    {
      "dir": "engines",
      "fileCount": 357
    },
    {
      "dir": "layouts",
      "fileCount": 3
    },
    {
      "dir": "middleware",
      "fileCount": 1
    },
    {
      "dir": "modules",
      "fileCount": 1
    },
    {
      "dir": "pages",
      "fileCount": 47
    },
    {
      "dir": "plugins",
      "fileCount": 5
    },
    {
      "dir": "prisma",
      "fileCount": 13
    },
    {
      "dir": "public",
      "fileCount": 8
    },
    {
      "dir": "scripts",
      "fileCount": 32
    },
    {
      "dir": "server",
      "fileCount": 254
    },
    {
      "dir": "stores",
      "fileCount": 0
    },
    {
      "dir": "tests",
      "fileCount": 60
    },
    {
      "dir": "types",
      "fileCount": 1
    }
  ],
  "api": [
    {
      "method": "GET",
      "path": "/api/admin/backup",
      "file": "server/api/admin/backup/index.get.ts",
      "summary": "备份中心：列表 + 体检（2026-10-07 · P1「安全与效率」第 1 条） 【权限】`backup:manage`（**GET 也要登记** ✓ —— 这个列表一按\"下载\"就是全站数据，",
      "permission": "backup:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "DELETE",
      "path": "/api/admin/backup/:name",
      "file": "server/api/admin/backup/[name].delete.ts",
      "summary": "删除一份备份（2026-10-07 · P1） ⚠️ 删掉的是**站点数据的一份拷贝** ⇒ 写操作日志 ✓，且**连带删 meta**（不留孤儿文件 ✗）。",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "name"
      ],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/backup/create",
      "file": "server/api/admin/backup/create.post.ts",
      "summary": "生成一份备份（2026-10-07 · P1） 【单飞】同一时刻只允许一个备份在跑 ✗ ——",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/backup/download",
      "file": "server/api/admin/backup/download.get.ts",
      "summary": "下载备份文件到本地（2026-10-07 · P1） 【为什么必须流式】备份里可能装的是几百 MB 的上传文件夹 ✗ ——",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/backup/restore",
      "file": "server/api/admin/backup/restore.post.ts",
      "summary": "上传一份备份并**预览**（第一步：只看不动 ✓ —— 2026-10-07 · P1） 【分两步，为什么】恢复会**覆盖全站数据** ⇒ 必须先让站主看见\"这份包里到底有什么、要覆盖什么\"，",
      "permission": "backup:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/backup/restore-commit",
      "file": "server/api/admin/backup/restore-commit.post.ts",
      "summary": "确认执行恢复（第二步：真的写 ✗ —— 2026-10-07 · P1） 【权限】独立权限点 `backup:restore` ✓ —— \"备份\"与\"恢复（覆盖全站数据）\"不是同一件事 ✗",
      "permission": "backup:restore",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/blocks",
      "file": "server/api/admin/blocks.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/content-snippets",
      "file": "server/api/admin/content-snippets.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/content-snippets",
      "file": "server/api/admin/content-snippets.put.ts",
      "summary": "（未写说明）",
      "permission": "page:edit",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/dashboard",
      "file": "server/api/admin/dashboard.put.ts",
      "summary": "（未写说明）",
      "permission": "site:config",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "hiddenCards",
          "type": "array[]",
          "required": false
        },
        {
          "name": "hiddenShortcuts",
          "type": "array[]",
          "required": false
        },
        {
          "name": "cardOrder",
          "type": "array[]",
          "required": false
        },
        {
          "name": "shortcutOrder",
          "type": "array[]",
          "required": false
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/engines",
      "file": "server/api/admin/engines.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "DELETE",
      "path": "/api/admin/engines/:id",
      "file": "server/api/admin/engines/[id].delete.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/engines/:id",
      "file": "server/api/admin/engines/[id].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": [
        {
          "name": "type",
          "type": "enum",
          "required": true
        },
        {
          "name": "enabled",
          "type": "boolean",
          "required": false
        },
        {
          "name": "settings",
          "type": "record",
          "required": false
        }
      ]
    },
    {
      "method": "DELETE",
      "path": "/api/admin/engines/:id/license",
      "file": "server/api/admin/engines/[id]/license.delete.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/engines/:id/license",
      "file": "server/api/admin/engines/[id]/license.put.ts",
      "summary": "（未写说明）",
      "permission": "engine:install",
      "auth": "RBAC",
      "pathParams": [
        "id"
      ],
      "bodyFields": [
        {
          "name": "type",
          "type": "enum",
          "required": true
        },
        {
          "name": "license",
          "type": "string",
          "required": true
        }
      ]
    },
    {
      "method": "POST",
      "path": "/api/admin/engines/:id/rollback",
      "file": "server/api/admin/engines/[id]/rollback.post.ts",
      "summary": "（未写说明）",
      "permission": "engine:install",
      "auth": "RBAC",
      "pathParams": [
        "id"
      ],
      "bodyFields": [
        {
          "name": "type",
          "type": "enum",
          "required": true
        },
        {
          "name": "name",
          "type": "string",
          "required": true
        }
      ]
    },
    {
      "method": "POST",
      "path": "/api/admin/engines/disable-third-party",
      "file": "server/api/admin/engines/disable-third-party.post.ts",
      "summary": "（未写说明）",
      "permission": "engine:install",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/engines/install",
      "file": "server/api/admin/engines/install.post.ts",
      "summary": "（未写说明）",
      "permission": "engine:install",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/engines/market",
      "file": "server/api/admin/engines/market.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/engines/reload",
      "file": "server/api/admin/engines/reload.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/engines/theme",
      "file": "server/api/admin/engines/theme.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/engines/theme",
      "file": "server/api/admin/engines/theme.put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "id",
          "type": "string",
          "required": false
        },
        {
          "name": "values",
          "type": "record",
          "required": false
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/engines/trust",
      "file": "server/api/admin/engines/trust.get.ts",
      "summary": "（未写说明）",
      "permission": "engine:install",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/engines/trust",
      "file": "server/api/admin/engines/trust.post.ts",
      "summary": "（未写说明）",
      "permission": "engine:install",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "publicKey",
          "type": "string",
          "required": true
        },
        {
          "name": "author",
          "type": "string",
          "required": false
        },
        {
          "name": "note",
          "type": "string",
          "required": false
        }
      ]
    },
    {
      "method": "DELETE",
      "path": "/api/admin/engines/trust/:keyId",
      "file": "server/api/admin/engines/trust/[keyId].delete.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "keyId"
      ],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/engines/trust/:keyId",
      "file": "server/api/admin/engines/trust/[keyId].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "keyId"
      ],
      "bodyFields": [
        {
          "name": "action",
          "type": "enum",
          "required": true
        }
      ]
    },
    {
      "method": "POST",
      "path": "/api/admin/forgot",
      "file": "server/api/admin/forgot.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "username",
          "type": "string",
          "required": true
        },
        {
          "name": "channel",
          "type": "enum",
          "required": true
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/forms",
      "file": "server/api/admin/forms.get.ts",
      "summary": "（未写说明）",
      "permission": "form:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/forms",
      "file": "server/api/admin/forms.post.ts",
      "summary": "（未写说明）",
      "permission": "form:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "key",
          "type": "unknown",
          "required": true
        },
        {
          "name": "name",
          "type": "string",
          "required": true
        },
        {
          "name": "fields",
          "type": "unknown",
          "required": true
        },
        {
          "name": "enabled",
          "type": "boolean",
          "required": false
        }
      ]
    },
    {
      "method": "DELETE",
      "path": "/api/admin/forms/:id",
      "file": "server/api/admin/forms/[id].delete.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/forms/:id",
      "file": "server/api/admin/forms/[id].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": [
        {
          "name": "name",
          "type": "string",
          "required": false
        },
        {
          "name": "fields",
          "type": "unknown",
          "required": false
        },
        {
          "name": "enabled",
          "type": "boolean",
          "required": false
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/forms/:id/export",
      "file": "server/api/admin/forms/[id]/export.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/forms/:id/submissions",
      "file": "server/api/admin/forms/[id]/submissions.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/friend-links",
      "file": "server/api/admin/friend-links.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/friend-links",
      "file": "server/api/admin/friend-links.put.ts",
      "summary": "（未写说明）",
      "permission": "nav:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/home-content",
      "file": "server/api/admin/home-content.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/home-content",
      "file": "server/api/admin/home-content.put.ts",
      "summary": "（未写说明）",
      "permission": "page:edit",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "content",
          "type": "record",
          "required": true
        }
      ]
    },
    {
      "method": "POST",
      "path": "/api/admin/login",
      "file": "server/api/admin/login.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/logout",
      "file": "server/api/admin/logout.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/me",
      "file": "server/api/admin/me.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/me/password",
      "file": "server/api/admin/me/password.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "currentPassword",
          "type": "string",
          "required": true
        },
        {
          "name": "newPassword",
          "type": "string",
          "required": true
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/media",
      "file": "server/api/admin/media.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "DELETE",
      "path": "/api/admin/media/:id",
      "file": "server/api/admin/media/[id].delete.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/media/:id",
      "file": "server/api/admin/media/[id].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": [
        {
          "name": "alt",
          "type": "string",
          "required": false
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/members",
      "file": "server/api/admin/members/index.get.ts",
      "summary": "（未写说明）",
      "permission": "member:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/members/:id",
      "file": "server/api/admin/members/[id].get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/members/:id",
      "file": "server/api/admin/members/[id].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/members/export",
      "file": "server/api/admin/members/export.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/metrics",
      "file": "server/api/admin/metrics.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/nav",
      "file": "server/api/admin/nav.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/nav",
      "file": "server/api/admin/nav.post.ts",
      "summary": "（未写说明）",
      "permission": "nav:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "scope",
          "type": "enum",
          "required": true
        },
        {
          "name": "label",
          "type": "string",
          "required": true
        },
        {
          "name": "href",
          "type": "string",
          "required": true
        },
        {
          "name": "parentId",
          "type": "string",
          "required": false
        },
        {
          "name": "description",
          "type": "string",
          "required": false
        },
        {
          "name": "icon",
          "type": "string",
          "required": false
        },
        {
          "name": "sort",
          "type": "number",
          "required": false
        },
        {
          "name": "enabled",
          "type": "boolean",
          "required": false
        }
      ]
    },
    {
      "method": "DELETE",
      "path": "/api/admin/nav/:id",
      "file": "server/api/admin/nav/[id].delete.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/nav/:id",
      "file": "server/api/admin/nav/[id].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": [
        {
          "name": "label",
          "type": "string",
          "required": false
        },
        {
          "name": "href",
          "type": "string",
          "required": false
        },
        {
          "name": "parentId",
          "type": "string",
          "required": false
        },
        {
          "name": "description",
          "type": "string",
          "required": false
        },
        {
          "name": "icon",
          "type": "string",
          "required": false
        },
        {
          "name": "sort",
          "type": "number",
          "required": false
        },
        {
          "name": "enabled",
          "type": "boolean",
          "required": false
        }
      ]
    },
    {
      "method": "POST",
      "path": "/api/admin/nav/:id/move",
      "file": "server/api/admin/nav/[id]/move.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": [
        {
          "name": "dir",
          "type": "enum",
          "required": true
        },
        {
          "name": "where",
          "type": "unknown",
          "required": true
        },
        {
          "name": "orderBy",
          "type": "unknown",
          "required": true
        }
      ]
    },
    {
      "method": "POST",
      "path": "/api/admin/notify/broadcast",
      "file": "server/api/admin/notify/broadcast.post.ts",
      "summary": "（未写说明）",
      "permission": "notify:broadcast",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/notify/channels",
      "file": "server/api/admin/notify/channels.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/notify/logs",
      "file": "server/api/admin/notify/logs.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/notify/logs/:id/retry",
      "file": "server/api/admin/notify/logs/[id]/retry.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/notify/messages",
      "file": "server/api/admin/notify/messages.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PATCH",
      "path": "/api/admin/notify/messages",
      "file": "server/api/admin/notify/messages.patch.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/notify/test",
      "file": "server/api/admin/notify/test.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/operation-logs",
      "file": "server/api/admin/operation-logs.get.ts",
      "summary": "（未写说明）",
      "permission": "log:view",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/pages",
      "file": "server/api/admin/pages.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/pages",
      "file": "server/api/admin/pages.post.ts",
      "summary": "（未写说明）",
      "permission": "page:edit",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "pageKey",
          "type": "string",
          "required": true
        },
        {
          "name": "title",
          "type": "string",
          "required": true
        },
        {
          "name": "summary",
          "type": "string",
          "required": false
        },
        {
          "name": "content",
          "type": "string",
          "required": false
        },
        {
          "name": "published",
          "type": "boolean",
          "required": false
        }
      ]
    },
    {
      "method": "DELETE",
      "path": "/api/admin/pages/:key",
      "file": "server/api/admin/pages/[key].delete.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "key"
      ],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/pages/:key",
      "file": "server/api/admin/pages/[key].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "key"
      ],
      "bodyFields": [
        {
          "name": "title",
          "type": "string",
          "required": false
        },
        {
          "name": "summary",
          "type": "string",
          "required": false
        },
        {
          "name": "content",
          "type": "string",
          "required": false
        },
        {
          "name": "blocks",
          "type": "array[]",
          "required": true
        },
        {
          "name": "settings",
          "type": "record",
          "required": false
        },
        {
          "name": "published",
          "type": "boolean",
          "required": false
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/performance",
      "file": "server/api/admin/performance.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/permissions",
      "file": "server/api/admin/permissions.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/reset",
      "file": "server/api/admin/reset.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "ticket",
          "type": "string",
          "required": true
        },
        {
          "name": "code",
          "type": "union",
          "required": false
        },
        {
          "name": "password",
          "type": "string",
          "required": true
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/roles",
      "file": "server/api/admin/roles.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/roles",
      "file": "server/api/admin/roles.post.ts",
      "summary": "（未写说明）",
      "permission": "rbac:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "name",
          "type": "string",
          "required": true
        },
        {
          "name": "permissions",
          "type": "array[]",
          "required": false
        }
      ]
    },
    {
      "method": "DELETE",
      "path": "/api/admin/roles/:id",
      "file": "server/api/admin/roles/[id].delete.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/roles/:id",
      "file": "server/api/admin/roles/[id].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": [
        {
          "name": "permissions",
          "type": "array[]",
          "required": true
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/search-terms",
      "file": "server/api/admin/search-terms.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/seo",
      "file": "server/api/admin/seo.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/seo/pages/:pageKey",
      "file": "server/api/admin/seo/pages/[pageKey].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "pageKey"
      ],
      "bodyFields": [
        {
          "name": "title",
          "type": "string",
          "required": false
        },
        {
          "name": "description",
          "type": "string",
          "required": false
        },
        {
          "name": "keywords",
          "type": "string",
          "required": false
        },
        {
          "name": "robots",
          "type": "string",
          "required": false
        },
        {
          "name": "ogImage",
          "type": "string",
          "required": false
        }
      ]
    },
    {
      "method": "POST",
      "path": "/api/admin/seo/push",
      "file": "server/api/admin/seo/push.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "scope",
          "type": "enum",
          "required": false
        },
        {
          "name": "urls",
          "type": "array[]",
          "required": false
        }
      ]
    },
    {
      "method": "PUT",
      "path": "/api/admin/seo/site",
      "file": "server/api/admin/seo/site.put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "items",
          "type": "array[]",
          "required": true
        },
        {
          "name": "key",
          "type": "string",
          "required": true
        },
        {
          "name": "value",
          "type": "string",
          "required": false
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/sidebar",
      "file": "server/api/admin/sidebar.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/site-config",
      "file": "server/api/admin/site-config.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/site-config/:key",
      "file": "server/api/admin/site-config/[key].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "key"
      ],
      "bodyFields": [
        {
          "name": "value",
          "type": "string",
          "required": false
        },
        {
          "name": "where",
          "type": "unknown",
          "required": true
        },
        {
          "name": "update",
          "type": "unknown",
          "required": true
        },
        {
          "name": "create",
          "type": "unknown",
          "required": true
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/site-pages",
      "file": "server/api/admin/site-pages.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/site-texts/:key",
      "file": "server/api/admin/site-texts/[key].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "key"
      ],
      "bodyFields": [
        {
          "name": "value",
          "type": "string",
          "required": true
        },
        {
          "name": "note",
          "type": "string",
          "required": false
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/staff",
      "file": "server/api/admin/staff.get.ts",
      "summary": "（未写说明）",
      "permission": "staff:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/staff",
      "file": "server/api/admin/staff.post.ts",
      "summary": "（未写说明）",
      "permission": "staff:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "username",
          "type": "string",
          "required": true
        },
        {
          "name": "name",
          "type": "string",
          "required": true
        },
        {
          "name": "password",
          "type": "string",
          "required": true
        },
        {
          "name": "roleId",
          "type": "string",
          "required": true
        },
        {
          "name": "email",
          "type": "union",
          "required": false
        },
        {
          "name": "phone",
          "type": "union",
          "required": false
        },
        {
          "name": "status",
          "type": "enum",
          "required": false
        },
        {
          "name": "opAllow",
          "type": "array[]",
          "required": false
        },
        {
          "name": "columnScope",
          "type": "array[]",
          "required": false
        },
        {
          "name": "featureScope",
          "type": "array[]",
          "required": false
        },
        {
          "name": "localeScope",
          "type": "array[]",
          "required": false
        }
      ]
    },
    {
      "method": "DELETE",
      "path": "/api/admin/staff/:id",
      "file": "server/api/admin/staff/[id].delete.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "PUT",
      "path": "/api/admin/staff/:id",
      "file": "server/api/admin/staff/[id].put.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [
        "id"
      ],
      "bodyFields": [
        {
          "name": "username",
          "type": "string",
          "required": false
        },
        {
          "name": "name",
          "type": "string",
          "required": false
        },
        {
          "name": "password",
          "type": "string",
          "required": false
        },
        {
          "name": "roleId",
          "type": "string",
          "required": false
        },
        {
          "name": "email",
          "type": "union",
          "required": false
        },
        {
          "name": "phone",
          "type": "union",
          "required": false
        },
        {
          "name": "status",
          "type": "enum",
          "required": false
        },
        {
          "name": "opAllow",
          "type": "array[]",
          "required": false
        },
        {
          "name": "columnScope",
          "type": "array[]",
          "required": false
        },
        {
          "name": "featureScope",
          "type": "array[]",
          "required": false
        },
        {
          "name": "localeScope",
          "type": "array[]",
          "required": false
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/admin/staff/options",
      "file": "server/api/admin/staff/options.get.ts",
      "summary": "（未写说明）",
      "permission": "staff:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/admin/stats",
      "file": "server/api/admin/stats.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "JWT",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/admin/upload",
      "file": "server/api/admin/upload.post.ts",
      "summary": "（未写说明）",
      "permission": "media:manage",
      "auth": "RBAC",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/auth/forgot",
      "file": "server/api/auth/forgot.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/auth/login",
      "file": "server/api/auth/login.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/auth/logout",
      "file": "server/api/auth/logout.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/auth/me",
      "file": "server/api/auth/me.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/auth/register",
      "file": "server/api/auth/register.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/auth/reset",
      "file": "server/api/auth/reset.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/csrf",
      "file": "server/api/csrf.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/dev-docs",
      "file": "server/api/dev-docs.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/developer/me",
      "file": "server/api/developer/me.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/developer/packages/commit",
      "file": "server/api/developer/packages/commit.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/developer/packages/inspect",
      "file": "server/api/developer/packages/inspect.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/developer/source",
      "file": "server/api/developer/source.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/engine/packages",
      "file": "server/api/engine/packages.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/engine/packages/:type/:id/download",
      "file": "server/api/engine/packages/[type]/[id]/download.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [
        "type",
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/engine/packages/:type/:id/source",
      "file": "server/api/engine/packages/[type]/[id]/source.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [
        "type",
        "id"
      ],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/engine/ui",
      "file": "server/api/engine/ui.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/engines",
      "file": "server/api/engines.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/forms/:key",
      "file": "server/api/forms/[key].get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [
        "key"
      ],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/forms/:key/submit",
      "file": "server/api/forms/[key]/submit.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [
        "key"
      ],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/friend-links",
      "file": "server/api/friend-links.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/health",
      "file": "server/api/health.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/home-content",
      "file": "server/api/home-content.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/member/leads",
      "file": "server/api/member/leads.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "会员",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/member/messages",
      "file": "server/api/member/messages.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "会员",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PATCH",
      "path": "/api/member/messages",
      "file": "server/api/member/messages.patch.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "会员",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/member/password",
      "file": "server/api/member/password.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "会员",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "PATCH",
      "path": "/api/member/profile",
      "file": "server/api/member/profile.patch.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "会员",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/metrics/web-vitals",
      "file": "server/api/metrics/web-vitals.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": [
        {
          "name": "metric",
          "type": "string",
          "required": true
        },
        {
          "name": "value",
          "type": "number",
          "required": true
        },
        {
          "name": "pagePath",
          "type": "string",
          "required": true
        },
        {
          "name": "userAgent",
          "type": "string",
          "required": false
        }
      ]
    },
    {
      "method": "GET",
      "path": "/api/nav",
      "file": "server/api/nav.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/pages",
      "file": "server/api/pages.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/search",
      "file": "server/api/search.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "POST",
      "path": "/api/search/hit",
      "file": "server/api/search/hit.post.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/search/hot",
      "file": "server/api/search/hot.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/seo",
      "file": "server/api/seo.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/site-config",
      "file": "server/api/site-config.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/site-texts",
      "file": "server/api/site-texts.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/taxonomy/tags",
      "file": "server/api/taxonomy/tags.get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [],
      "bodyFields": []
    },
    {
      "method": "GET",
      "path": "/api/taxonomy/tags/:slug",
      "file": "server/api/taxonomy/tags/[slug].get.ts",
      "summary": "（未写说明）",
      "permission": "",
      "auth": "公开",
      "pathParams": [
        "slug"
      ],
      "bodyFields": []
    }
  ],
  "middleware": [
    {
      "file": "server/middleware/admin-auth.ts",
      "summary": ""
    },
    {
      "file": "server/middleware/csrf.ts",
      "summary": ""
    },
    {
      "file": "server/middleware/indexnow-key.ts",
      "summary": ""
    },
    {
      "file": "server/middleware/maintenance.ts",
      "summary": ""
    },
    {
      "file": "server/middleware/request-id.ts",
      "summary": "每个请求一个短编号（8 位十六进制），挂在 `event.context.requestId` 并回写成响应头 `x-request-id`。 【为什么需要】以前出 500 时，日志里只有一行 `[req] GET /api/search → 500 57ms`"
    },
    {
      "file": "server/middleware/request-log.ts",
      "summary": ""
    },
    {
      "file": "server/middleware/security.ts",
      "summary": ""
    },
    {
      "file": "server/middleware/seo-verify-file.ts",
      "summary": ""
    }
  ],
  "nitroPlugins": [
    {
      "file": "server/plugins/csp-hashes.ts",
      "summary": ""
    },
    {
      "file": "server/plugins/engine.ts",
      "summary": ""
    },
    {
      "file": "server/plugins/error-report.ts",
      "summary": "500（及其它未处理的服务端异常）的统一留痕。 【为什么要这一层】此前唯一的留痕是 request-log 里的一行摘要："
    },
    {
      "file": "server/plugins/front-css.ts",
      "summary": ""
    },
    {
      "file": "server/plugins/noise-filter.ts",
      "summary": "dev 日志降噪：过滤「同名组件重复注册」这一条 Vue 警告。 【为什么这条是噪音，不是问题】"
    },
    {
      "file": "server/plugins/seo-autopush.ts",
      "summary": ""
    },
    {
      "file": "server/plugins/startup-checks.ts",
      "summary": "启动自检（基座 M0 止血） 【为什么必须有这一步】server/utils/auth.ts 在 NUXT_JWT_SECRET 未配置时会回退到"
    },
    {
      "file": "server/plugins/theme-css.ts",
      "summary": "主题样式按路由注入：**前台注入、后台绝不注入** 【为什么必须是这个形状】主题的 CSS 一旦进 Vite（不管是 `nuxt.options.css`，还是放在主题布局里"
    }
  ],
  "serverRoutes": [
    {
      "file": "server/routes/api/v1/[...path].ts",
      "summary": ""
    },
    {
      "file": "server/routes/engine-assets/[...path].get.ts",
      "summary": ""
    },
    {
      "file": "server/routes/robots.txt.get.ts",
      "summary": "robots.txt（PRD SEO 规范 7.2） 之前全站没有这个文件，/robots.txt 直接 404 —— 但 sitemap.xml 已经做好了，"
    },
    {
      "file": "server/routes/sitemap.txt.get.ts",
      "summary": ""
    },
    {
      "file": "server/routes/sitemap.xml.get.ts",
      "summary": ""
    }
  ],
  "serverUtils": [
    {
      "file": "server/utils/admin/dashboard.ts",
      "summary": "仪表盘卡片注册表（P1-6，**唯一真源**） 【站主要什么】\"仪表盘卡片要能注册、能开关、能排序\" ✓。"
    },
    {
      "file": "server/utils/admin/grants.ts",
      "summary": "「这个管理员这一次请求能不能做」的**裁决层**（纯函数，单测直接 import ✓） 【为什么单独一层，不把判断散在中间件里】站主要的四件事（新增 / 修改 / 删除 · 指定语言 ·"
    },
    {
      "file": "server/utils/admin/nav.ts",
      "summary": "P1-5：侧栏可见性与接口鉴权**共用同一套权限**（`hasPermission` 认超管通配 `*` ✓）—— 这就是\"双轨合一\"：不再有第二套 `role === 'super_admin'` 的判据 ✓。"
    },
    {
      "file": "server/utils/admin/role-presets.ts",
      "summary": "内置用户组（站主 2026-10-07 需求①：创始人 / 管理员 / 内容管理员 / 优化推广员 / 自定义用户组） 【为什么要有这个文件】改前\"谁能干什么\"只存在于两个地方："
    },
    {
      "file": "server/utils/admin/scopes.ts",
      "summary": "管理员**可授予范围**的唯一真源（站主 2026-10-07 需求②：指定语言 / 指定栏目 / 指定功能） 【为什么要单独一个文件】这三个词在站主的话里是一句带过，落到系统上却是**三张各自独立的清单**："
    },
    {
      "file": "server/utils/admin/staff.ts",
      "summary": "管理员管理的**共用校验与格式化**（2026-10-07） 【为什么抽这一层】staff 有 5 个端点（列表 / 选项 / 新增 / 编辑 / 删除 / 代改密码），"
    },
    {
      "file": "server/utils/admin-password-reset.ts",
      "summary": ""
    },
    {
      "file": "server/utils/api-changelog.ts",
      "summary": "API 与数据结构的**变更记录**（纯逻辑，可单测） 【它解决什么问题】接口是二次开发者的合同，但合同是会改的："
    },
    {
      "file": "server/utils/api-error.ts",
      "summary": ""
    },
    {
      "file": "server/utils/audit.ts",
      "summary": ""
    },
    {
      "file": "server/utils/auth.ts",
      "summary": ""
    },
    {
      "file": "server/utils/backup/create.ts",
      "summary": "生成备份（2026-10-07 · P1「安全与效率」） 【站主要的三形态】单独备份数据库 / 单独备份上传文件夹 / 一键整站 —— 这三种只是 `parts` 不同 ✓，"
    },
    {
      "file": "server/utils/backup/database.ts",
      "summary": "数据库备份 / 恢复基座（2026-10-07 · P1「安全与效率」） 【两条路线，为什么】"
    },
    {
      "file": "server/utils/backup/restore.ts",
      "summary": "从备份恢复（2026-10-07 · P1「安全与效率」） 【这是全后台最危险的动作】它会**覆盖全站数据** ⇒ 三条纪律："
    },
    {
      "file": "server/utils/backup/store.ts",
      "summary": "备份文件的存放与清单（2026-10-07 · P1「安全与效率」） 【放哪儿】默认 `<项目根>/storage/backups`，`HEJUN_BACKUP_DIR` 可覆盖 ✗ **绝不放 public/ 下**："
    },
    {
      "file": "server/utils/backup/tar.ts",
      "summary": "流式 tar.gz —— 备份与恢复的底座（2026-10-07 · P1「安全与效率」） 【为什么不用项目里已有的 nanotar】"
    },
    {
      "file": "server/utils/block-components.ts",
      "summary": ""
    },
    {
      "file": "server/utils/content-cache.ts",
      "summary": "内容缓存内核（基座）—— **服务端那一半的内容契约** 【它补的是什么】前端有 `useSiteContent`（契约 v1.0.0，M1 完成）把接口结果归一化成稳定形状；"
    },
    {
      "file": "server/utils/content-snippets.ts",
      "summary": ""
    },
    {
      "file": "server/utils/csp.ts",
      "summary": ""
    },
    {
      "file": "server/utils/csrf.ts",
      "summary": ""
    },
    {
      "file": "server/utils/db.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/api-perms.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/auto-import-names.ts",
      "summary": "扩展接口里可以直接使用的「自动导入」名字（唯一权威清单） 【为什么需要这个概念】"
    },
    {
      "file": "server/utils/engine/auto-imports.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/backup.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/build-gc.ts",
      "summary": "产物目录的通用回收工具（纯 fs 工具，不含业务判定） 判定「哪些该留」在各自的清单模块里："
    },
    {
      "file": "server/utils/engine/build-inventory.ts",
      "summary": "扩展**接口**（服务端）产物的「清单守卫」（纯函数：不碰 fs，可单测） 与 UI 线（ui-inventory.ts）同一套规则，区别只有产物命名："
    },
    {
      "file": "server/utils/engine/core-routes.generated.ts",
      "summary": "由 modules/engine.ts 在构建时自动生成，请勿手改（每次启动/构建都会覆盖）。 内容一：核心自带的接口路由清单（`METHOD /path`，动态段写成 `:param`）。"
    },
    {
      "file": "server/utils/engine/dispatch.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/graph.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/heavy-deps.ts",
      "summary": "重型编译依赖的延迟加载（**必须**用「变量说明符 + 动态 import」，不要改成静态 import） 【为什么这条规则这么硬 —— 一次整站 500 的教训】"
    },
    {
      "file": "server/utils/engine/hooks.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/hosts.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/index-format.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/install.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/license-store.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/license.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/manifest-schema.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/manifest.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/market-catalog.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/market-index.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/package-source.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/perm-table.ts",
      "summary": "扩展权限表汇总（纯函数，无 IO） 单独拆出来的原因与 graph.ts 相同：这段逻辑原来与数据库查询写在一起，"
    },
    {
      "file": "server/utils/engine/pure-frontend.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/regions.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/registry.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/reload.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/routes.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/runtime.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/scan.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/settings.ts",
      "summary": "扩展设置的归一化（基座 C 项收口） 【解决什么】`EnginePackage.settings` 原本是\"无 schema 的 JSON\"：值一律按字符串存"
    },
    {
      "file": "server/utils/engine/sfc.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/signing.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/submission-review.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/surface.ts",
      "summary": "运行面（surface）判据 —— **后台轨道与前台轨道的唯一分界点**。 【为什么必须有这个文件】站主 2026-09-30 的判断：「后台的页面会涉及到前台的显示，这个明显就是"
    },
    {
      "file": "server/utils/engine/theme-assembly.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/theme-contract.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/theme-validate.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/theme.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/trust-store.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/trust.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/ui-bridge.ts",
      "summary": "引擎 UI 运行时桥（**刻意零依赖**：Nitro 侧与 Nuxt 应用侧都会 import 它） 【为什么需要这个文件】"
    },
    {
      "file": "server/utils/engine/ui-inventory.ts",
      "summary": "运行时 UI 产物的「清单守卫」（纯函数：不碰 fs / nitro / vue，可直接单测） 管两件底层边界的事："
    },
    {
      "file": "server/utils/engine/ui-shims.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/ui-table.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/ui-usable.ts",
      "summary": "运行时 UI 产物「是否可渲染」的判定（纯函数，可单测） 【为什么需要它】扩展的组件/页面是服务端就地编译出来的（server/utils/engine/sfc.ts），"
    },
    {
      "file": "server/utils/engine/ui.ts",
      "summary": ""
    },
    {
      "file": "server/utils/engine/uninstall.ts",
      "summary": ""
    },
    {
      "file": "server/utils/forms.ts",
      "summary": ""
    },
    {
      "file": "server/utils/friend-links.ts",
      "summary": ""
    },
    {
      "file": "server/utils/home-content.ts",
      "summary": "首页内容（形状 + 解析 + 规范化） 【它是什么】首页各段内容存在 `SiteConfig.home_content`（JSON 字符串，见 site-config-registry.ts），"
    },
    {
      "file": "server/utils/jobs.ts",
      "summary": ""
    },
    {
      "file": "server/utils/member-auth.ts",
      "summary": ""
    },
    {
      "file": "server/utils/member-identity.ts",
      "summary": "会员登录标识：双通道（手机号或邮箱）。 【为什么单独一个文件】注册、登录、会员改资料、以及\"线索按手机号挂到会员\"都要用同一套"
    },
    {
      "file": "server/utils/member-reset.ts",
      "summary": ""
    },
    {
      "file": "server/utils/metrics.ts",
      "summary": ""
    },
    {
      "file": "server/utils/nav-defaults.ts",
      "summary": "内置默认导航（基座 M1） 【唯一事实在服务端】公开接口 `/api/nav` 在某个 scope 没有任何启用条目时回落到这里，"
    },
    {
      "file": "server/utils/notify-templates.ts",
      "summary": "通知**事件**与**正文模板**（唯一真源，2026-10-06 P0-3） 【站主要什么】\"通知没做对应要有设置和开关\" —— 上一轮（P0-2 之前）已经把**通道**开关做完了 ✓"
    },
    {
      "file": "server/utils/notify.ts",
      "summary": ""
    },
    {
      "file": "server/utils/perm-match.ts",
      "summary": "「方法 + 路径 → 权限键」的匹配规则（纯函数，核心与扩展**共用同一套**） 【为什么必须共用】核心的 route-perms.ts 与扩展的 api-perms.ts（模块在清单里声明的权限点）"
    },
    {
      "file": "server/utils/permissions.ts",
      "summary": "RBAC 权限清单（PRD 5.7 颗粒度：页面访问 / 新增 / 编辑 / 删除 / 导出） ⚠️ 与 server/middleware/admin-auth.ts 的 ROUTE_PERMS 一一对应："
    },
    {
      "file": "server/utils/public-content.ts",
      "summary": ""
    },
    {
      "file": "server/utils/push-paths.ts",
      "summary": ""
    },
    {
      "file": "server/utils/push-plan.ts",
      "summary": ""
    },
    {
      "file": "server/utils/push-quota.ts",
      "summary": "推送配额相关的纯逻辑（2026-09-30） 【为什么会有这个文件】站主第一次手动全量推送就撞上百度的 `over quota`："
    },
    {
      "file": "server/utils/rate-limit.ts",
      "summary": ""
    },
    {
      "file": "server/utils/redis.ts",
      "summary": ""
    },
    {
      "file": "server/utils/route-perms.ts",
      "summary": "后台路由 → 所需权限 的映射与匹配（PRD 5.7） 抽成独立纯函数是为了能直接单测 —— 这段逻辑一旦写错，"
    },
    {
      "file": "server/utils/search-push.ts",
      "summary": ""
    },
    {
      "file": "server/utils/seo-config.ts",
      "summary": ""
    },
    {
      "file": "server/utils/seo-page-keys.ts",
      "summary": ""
    },
    {
      "file": "server/utils/seo-pages.ts",
      "summary": "可在后台单独设置 SEO 的页面清单 只列「路径固定」的页面。系统详情页 /systems/:slug 与版本日志页不在这里 ——"
    },
    {
      "file": "server/utils/seo-verify.ts",
      "summary": "搜索引擎「站点验证」的单一真源（2026-09-30） 【为什么需要这个文件】原先验证码是**三个写死的键**（google/bing/baidu）直接写在 `app.vue` 里，"
    },
    {
      "file": "server/utils/site-config-registry.ts",
      "summary": "站点配置注册表（基座 M0） 【它解决什么】SiteConfig 原本是\"无 schema 的 KV\"：键只存在于 seed、值全是字符串、"
    },
    {
      "file": "server/utils/site-texts.ts",
      "summary": ""
    },
    {
      "file": "server/utils/site-urls.ts",
      "summary": ""
    },
    {
      "file": "server/utils/sms-aliyun.ts",
      "summary": ""
    },
    {
      "file": "server/utils/source-package.ts",
      "summary": ""
    },
    {
      "file": "server/utils/wechat-mp.ts",
      "summary": "微信公众号模板消息（2026-10-06） 【门槛先写清楚】这条通道需要**已认证的服务号**（订阅号没有模板消息接口 ✗），"
    }
  ],
  "serverTasks": [
    {
      "file": "server/tasks/backup-auto.ts",
      "summary": "每天自动备份整站（2026-10-07 补完 P9） 【为什么要有它】`docs/runbook.md` 一直写着\"建议每天 03:00 跑一次备份\" ✓ ——"
    },
    {
      "file": "server/tasks/cleanup-webvitals.ts",
      "summary": ""
    },
    {
      "file": "server/tasks/demo-recycle.ts",
      "summary": ""
    },
    {
      "file": "server/tasks/health-alert.ts",
      "summary": ""
    },
    {
      "file": "server/tasks/seo-full-push.ts",
      "summary": ""
    }
  ],
  "models": [
    {
      "name": "AdminUser",
      "comment": "管理员用户",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "username",
          "type": "String",
          "optional": false,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "passwordHash",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "name",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "roleId",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "role",
          "type": "AdminRole",
          "optional": false,
          "attrs": "@relation(fields: [roleId], references: [id])",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "rememberMe",
          "type": "Boolean",
          "optional": false,
          "attrs": "@default(false)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "/*",
          "type": "=====",
          "optional": false,
          "attrs": "2026-10-07 管理员管理（P2-11）=====",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "下面三组字段回答的是同一个问题：**这个账号能碰什么**。",
          "type": "undefined",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "⚠️",
          "type": "【空",
          "optional": false,
          "attrs": "= 不限制，这是硬约定】任何范围字段为空数组 ⇒ 该管理员的行为与本次改造前**完全一致**",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "（沿用角色的全部权限）✓。理由：站主给自己账号加了限制、或者批量给老账号一个默认值，",
          "type": "undefined",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "都可能**把自己关在外面**",
          "type": "✓",
          "optional": false,
          "attrs": "—— \"不限制\"是唯一安全的缺省语义 ✓。 */",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "/*",
          "type": "找回密码的两个投递地址",
          "optional": false,
          "attrs": "⚠️ **唯一**约束不要去掉：",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "它挡的是\"两个管理员写同一个手机号",
          "type": "⇒",
          "optional": false,
          "attrs": "短信验证码发给了不该拿到它的人\"。",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "可空列的多",
          "type": "NULL",
          "optional": false,
          "attrs": "在 Postgres 里是允许重复的 ✓ ⇒ 不填的人不受影响 ✓。 */",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "email",
          "type": "String?",
          "optional": true,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "phone",
          "type": "String?",
          "optional": true,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "/*",
          "type": "active",
          "optional": false,
          "attrs": "| disabled。停用≠删除：操作日志外键指向这个人，删了历史就断 ✗ */",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "status",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"active\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "/*",
          "type": "操作权限（站主要的那三项：新增",
          "optional": false,
          "attrs": "/ 修改 / 删除）。",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "存的是",
          "type": "CREATE",
          "optional": false,
          "attrs": "/ UPDATE / DELETE 三个动作名，空 = 不限。 */",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "opAllow",
          "type": "String[]",
          "optional": false,
          "attrs": "@default([])",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "/*",
          "type": "指定栏目：**内容板块**（页面内容",
          "optional": false,
          "attrs": "/ 常见问题 / 产品 / 版本日志 / 媒体库），",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "取值见",
          "type": "server/utils/admin/scopes.ts",
          "optional": false,
          "attrs": "的 COLUMN_SCOPES ✓（唯一真源），空 = 不限。 */",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "columnScope",
          "type": "String[]",
          "optional": false,
          "attrs": "@default([])",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "/*",
          "type": "指定功能：**后台功能模块**（站点配置",
          "optional": false,
          "attrs": "/ 搜索引擎 / 会员 / 表单 …），",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "取值见同一文件的",
          "type": "FEATURE_SCOPES",
          "optional": false,
          "attrs": "✓，空 = 不限。 */",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "featureScope",
          "type": "String[]",
          "optional": false,
          "attrs": "@default([])",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "/*",
          "type": "指定语言。⚠️",
          "optional": false,
          "attrs": "多语言目前只到\"预留列\"（PageContent.locale）⇒",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "这一维现在**先落库**，存的是多语言功能开放后要用的判据（现在还没有任何出口读它）——",
          "type": "界面上必须写明这一点",
          "optional": false,
          "attrs": "✗，",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "不许让人以为设了就有用",
          "type": "✓。",
          "optional": false,
          "attrs": "*/",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "localeScope",
          "type": "String[]",
          "optional": false,
          "attrs": "@default([])",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "lastLoginAt",
          "type": "DateTime?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "operationLogs",
          "type": "OperationLog[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        }
      ],
      "fieldCount": 36
    },
    {
      "name": "AdminRole",
      "comment": "角色权限 RBAC",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "/*",
          "type": "角色标识：**登录令牌里存的就是它**（见",
          "optional": false,
          "attrs": "login.post.ts 的 signToken）⇒ 创建后不可改，改名会让已登录用户对不上权限 ✓ */",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "name",
          "type": "String",
          "optional": false,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "/*",
          "type": "显示名（中文，界面上给站主看）。英文名",
          "optional": false,
          "attrs": "`name` 仍然唯一且稳定 ⇒ 两者分工，别混用 ✓ */",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "label",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "permissions",
          "type": "String[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "/*",
          "type": "内置组排在前面（顺序即选项顺序，稳定",
          "optional": false,
          "attrs": "⇒ 选项不会每次刷新都换位置） */",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "sort",
          "type": "Int",
          "optional": false,
          "attrs": "@default(0)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "users",
          "type": "AdminUser[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 11
    },
    {
      "name": "PageContent",
      "comment": "页面静态内容（首页、关于、共建等；基座 M3 起支持后台新建与发布状态）",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "pageKey",
          "type": "String",
          "optional": false,
          "attrs": "@unique // 页面标识：同时是路由 /{pageKey} 与导航候选",
          "isRelation": false,
          "note": "页面标识：同时是路由 /{pageKey} 与导航候选"
        },
        {
          "name": "title",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "summary",
          "type": "String?",
          "optional": true,
          "attrs": "// 一句话摘要（列表与 SEO description 用）",
          "isRelation": false,
          "note": "一句话摘要（列表与 SEO description 用）"
        },
        {
          "name": "content",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "published",
          "type": "Boolean",
          "optional": false,
          "attrs": "@default(true)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "settings",
          "type": "Json?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "locale",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "blocks",
          "type": "Json?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 11
    },
    {
      "name": "MediaAsset",
      "comment": "媒体库（基座 M3）：上传即登记，删除前查引用（产品图集/页面内容/SEO 分享图/站点配置）",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "url",
          "type": "String",
          "optional": false,
          "attrs": "@unique // /uploads/xxx.png",
          "isRelation": false,
          "note": "/uploads/xxx.png"
        },
        {
          "name": "mime",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "size",
          "type": "Int",
          "optional": false,
          "attrs": "// 字节",
          "isRelation": false,
          "note": "字节"
        },
        {
          "name": "alt",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "uploaderId",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 7
    },
    {
      "name": "Form",
      "comment": "防灌水：提交接口带蜜罐字段 _website（前台表单隐藏填写，机器人会填）+ 按 IP 限频。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "key",
          "type": "String",
          "optional": false,
          "attrs": "@unique // 提交接口 /api/forms/{key}/submit",
          "isRelation": false,
          "note": "提交接口 /api/forms/{key}/submit"
        },
        {
          "name": "name",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "fields",
          "type": "Json",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "enabled",
          "type": "Boolean",
          "optional": false,
          "attrs": "@default(true)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "submissions",
          "type": "FormSubmission[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        }
      ],
      "fieldCount": 8
    },
    {
      "name": "SiteConfig",
      "comment": "否则会随公开配置一起下发到浏览器。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "key",
          "type": "String",
          "optional": false,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "value",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "description",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 5
    },
    {
      "name": "SeoPageSetting",
      "comment": "单页 SEO 覆盖（后台「SEO 设置」按页面维护；留空则用页面上写死的默认值）",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "pageKey",
          "type": "String",
          "optional": false,
          "attrs": "@unique // 站点内的规范路径：/ , /about , /systems ...",
          "isRelation": false,
          "note": "站点内的规范路径：/ , /about , /systems ..."
        },
        {
          "name": "title",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "description",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "keywords",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "robots",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\") // 留空表示沿用页面默认（通常 index, follow）",
          "isRelation": false,
          "note": "留空表示沿用页面默认（通常 index, follow）"
        },
        {
          "name": "ogImage",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 9
    },
    {
      "name": "SeoPushLog",
      "comment": "搜索引擎推送记录（每次主动推送留痕，便于判断是否被收录前先确认推送成功）",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "scope",
          "type": "String",
          "optional": false,
          "attrs": "// all / urls / auto",
          "isRelation": false,
          "note": "all / urls / auto"
        },
        {
          "name": "urlCount",
          "type": "Int",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "engines",
          "type": "String",
          "optional": false,
          "attrs": "// 各引擎结果的 JSON 摘要",
          "isRelation": false,
          "note": "各引擎结果的 JSON 摘要"
        },
        {
          "name": "ok",
          "type": "Boolean",
          "optional": false,
          "attrs": "@default(false)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 6
    },
    {
      "name": "NavItem",
      "comment": "（server/utils/nav-defaults.ts），所以「从没配置过导航」与「今天的站点」完全一致。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "scope",
          "type": "String",
          "optional": false,
          "attrs": "// main / footer / admin",
          "isRelation": false,
          "note": "main / footer / admin"
        },
        {
          "name": "parentId",
          "type": "String?",
          "optional": true,
          "attrs": "// 二级菜单挂在一级的 id 上（只支持两层）",
          "isRelation": false,
          "note": "二级菜单挂在一级的 id 上（只支持两层）"
        },
        {
          "name": "label",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "href",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "description",
          "type": "String?",
          "optional": true,
          "attrs": "// 下拉里的说明文字（可选）",
          "isRelation": false,
          "note": "下拉里的说明文字（可选）"
        },
        {
          "name": "icon",
          "type": "String?",
          "optional": true,
          "attrs": "// 下拉卡片里的单字标识（可选）",
          "isRelation": false,
          "note": "下拉卡片里的单字标识（可选）"
        },
        {
          "name": "sort",
          "type": "Int",
          "optional": false,
          "attrs": "@default(0)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "enabled",
          "type": "Boolean",
          "optional": false,
          "attrs": "@default(true)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 11
    },
    {
      "name": "EnginePackage",
      "comment": "文件清单以构建期扫描结果为准（避免两边不一致时不知道该信谁）。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "type",
          "type": "String",
          "optional": false,
          "attrs": "// template / module / plugin",
          "isRelation": false,
          "note": "template / module / plugin"
        },
        {
          "name": "key",
          "type": "String",
          "optional": false,
          "attrs": "// 包的 id（目录名，与 manifest.id 一致）",
          "isRelation": false,
          "note": "包的 id（目录名，与 manifest.id 一致）"
        },
        {
          "name": "name",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "version",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "enabled",
          "type": "Boolean",
          "optional": false,
          "attrs": "@default(false)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "settings",
          "type": "Json?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "signerKeyId",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "installedFrom",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 11
    },
    {
      "name": "EngineTrustedKey",
      "comment": "吊销必须能随手做且立刻生效，环境变量做不到；环境变量保留为首次引导。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "keyId",
          "type": "String",
          "optional": false,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "publicKey",
          "type": "String",
          "optional": false,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "author",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "note",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "source",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"manual\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "revokedAt",
          "type": "DateTime?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 9
    },
    {
      "name": "EngineLicense",
      "comment": "两者不一致时以 raw 为准 —— 解析字段只是缓存，不参与判定。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "type",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "key",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "raw",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "licensedTo",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "domain",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "major",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "expiresAt",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "issuedAt",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "issuerKeyId",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "uploadedBy",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "note",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 14
    },
    {
      "name": "OperationLog",
      "comment": "管理员操作日志",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "/*",
          "type": "【2026-10-07",
          "optional": false,
          "attrs": "改成可空 + SetNull】站主要\"能删除管理员\" ✓，而改前是**必填 + Restrict** ✗：",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "任何登录过的管理员都会留下",
          "type": "`login`",
          "optional": false,
          "attrs": "日志 ⇒ 一律删不掉（prisma P2003 ✗），",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "表现是\"删除按钮点了报错\"，而真正的原因是\"他登录过\"",
          "type": "✓",
          "optional": false,
          "attrs": "—— 这不可能向站主解释得通 ✗。",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "现在：**删账号不再删日志**",
          "type": "✓（`detail`",
          "optional": false,
          "attrs": "里的事件原样保留 ✓，只是\"谁做的\"变成空 ✓）——",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "审计要的是\"发生过什么\"，不是\"那个用户名还在不在\"",
          "type": "✓。",
          "optional": false,
          "attrs": "*/",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "adminUserId",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "adminUser",
          "type": "AdminUser?",
          "optional": true,
          "attrs": "@relation(fields: [adminUserId], references: [id], onDelete: SetNull)",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "action",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "detail",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "ip",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 12
    },
    {
      "name": "WebVitalRecord",
      "comment": "Web Vitals性能指标记录",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "metric",
          "type": "String",
          "optional": false,
          "attrs": "// LCP / INP / CLS",
          "isRelation": false,
          "note": "LCP / INP / CLS"
        },
        {
          "name": "value",
          "type": "Float",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "pagePath",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "userAgent",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 6
    },
    {
      "name": "ProductLog",
      "comment": "版本日志（按产品分组）",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "productId",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "product",
          "type": "Product",
          "optional": false,
          "attrs": "@relation(fields: [productId], references: [id], onDelete: Cascade)",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "version",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updateType",
          "type": "String",
          "optional": false,
          "attrs": "//新增 / 优化 / 修复",
          "isRelation": false,
          "note": "新增 / 优化 / 修复"
        },
        {
          "name": "content",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 8
    },
    {
      "name": "DemoApplication",
      "comment": "系统演示申请 / 开通记录",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "productId",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "product",
          "type": "Product",
          "optional": false,
          "attrs": "@relation(fields: [productId], references: [id])",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "leadName",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "contact",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "tempAccount",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "expireAt",
          "type": "DateTime?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "status",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"pending\") // pending / active / expired",
          "isRelation": false,
          "note": "pending / active / expired"
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 10
    },
    {
      "name": "Faq",
      "comment": "常见问题（FAQ）：后台可维护，/faq 页与「联合共建」页共用同一数据源",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "question",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "answer",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "category",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"通用\") // 前台按分类分组展示",
          "isRelation": false,
          "note": "前台按分类分组展示"
        },
        {
          "name": "sortWeight",
          "type": "Int",
          "optional": false,
          "attrs": "@default(0) // 越大越靠前",
          "isRelation": false,
          "note": "越大越靠前"
        },
        {
          "name": "status",
          "type": "Boolean",
          "optional": false,
          "attrs": "@default(true) // true 前台显示 false 隐藏",
          "isRelation": false,
          "note": "true 前台显示 false 隐藏"
        },
        {
          "name": "deletedAt",
          "type": "DateTime?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 9
    },
    {
      "name": "Lead",
      "comment": "表里只存字符串 —— 状态集合是业务约定，不是数据库约束。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "name",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "company",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "contact",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "memberId",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "member",
          "type": "Member?",
          "optional": true,
          "attrs": "@relation(fields: [memberId], references: [id], onDelete: SetNull)",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "interestSlug",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "description",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "status",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"new\") // new / contacted / demo / negotiating / closed / archived",
          "isRelation": false,
          "note": "new / contacted / demo / negotiating / closed / archived"
        },
        {
          "name": "remark",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "deletedAt",
          "type": "DateTime?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 13
    },
    {
      "name": "Tag",
      "comment": "产品标签：只用于给产品分类，所以与产品同属一个模块",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "name",
          "type": "String",
          "optional": false,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "slug",
          "type": "String",
          "optional": false,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "products",
          "type": "Product[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 6
    },
    {
      "name": "Product",
      "comment": "自研业务系统（产品）",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "name",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "slug",
          "type": "String",
          "optional": false,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "shortDescription",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "description",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "painPoints",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "targetCustomer",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "features",
          "type": "String[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "imageGallery",
          "type": "String[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "deliveryType",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "deploymentMethod",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "status",
          "type": "Boolean",
          "optional": false,
          "attrs": "@default(false) // true上线 false隐藏",
          "isRelation": false,
          "note": "true上线 false隐藏"
        },
        {
          "name": "sortWeight",
          "type": "Int",
          "optional": false,
          "attrs": "@default(0)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "seoTitle",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "seoDescription",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "deletedAt",
          "type": "DateTime?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "deletedSlug",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "tags",
          "type": "Tag[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "changelogs",
          "type": "ProductLog[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "demoApplications",
          "type": "DemoApplication[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 22
    },
    {
      "name": "Member",
      "comment": "空串是一个**值**，两个空串就会撞唯一索引。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "email",
          "type": "String?",
          "optional": true,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "phone",
          "type": "String?",
          "optional": true,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "passwordHash",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "name",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "locale",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "status",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"active\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "leads",
          "type": "Lead[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        }
      ],
      "fieldCount": 10
    },
    {
      "name": "Term",
      "comment": "现有 ProductTag 数据由迁移脚本搬到这里（Term + TermLink），Tag 模型保留待模块下个版本切换。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "taxonomy",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "name",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "slug",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "sort",
          "type": "Int",
          "optional": false,
          "attrs": "@default(0)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "links",
          "type": "TermLink[]",
          "optional": false,
          "attrs": "",
          "isRelation": true,
          "note": ""
        }
      ],
      "fieldCount": 6
    },
    {
      "name": "TermLink",
      "comment": "分类与内容的通用关联：不外联具体表（targetType + targetId），一张表服务全部内容类型。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "termId",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "term",
          "type": "Term",
          "optional": false,
          "attrs": "@relation(fields: [termId], references: [id], onDelete: Cascade)",
          "isRelation": true,
          "note": ""
        },
        {
          "name": "targetType",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "targetId",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 5
    },
    {
      "name": "SiteText",
      "comment": "key 清单见 composables/text-registry.ts。",
      "fields": [
        {
          "name": "key",
          "type": "String",
          "optional": false,
          "attrs": "@id",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "value",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "note",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "updatedAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@updatedAt",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 4
    },
    {
      "name": "SearchTerm",
      "comment": "· 不做任何用户身份记录（没有 IP、没有会员 id）：这里统计的是\"词\"，不是\"人\"。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "term",
          "type": "String",
          "optional": false,
          "attrs": "@unique",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "count",
          "type": "Int",
          "optional": false,
          "attrs": "@default(0)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "lastAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 4
    },
    {
      "name": "Notification",
      "comment": "/ `audience` 区分收件人类型：`admin` = 后台管理员（当前唯一在用）、`member` = 会员（预留）。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "audience",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"admin\") // admin / member",
          "isRelation": false,
          "note": "admin / member"
        },
        {
          "name": "adminUserId",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "memberId",
          "type": "String?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "event",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "title",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "body",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "level",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"info\") // info / warn",
          "isRelation": false,
          "note": "info / warn"
        },
        {
          "name": "readAt",
          "type": "DateTime?",
          "optional": true,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 10
    },
    {
      "name": "NotifyLog",
      "comment": "/ `target` 存收件人标识，但**只留尾部**（邮箱/手机号是个人信息，别整串进库与日志 ✗）。",
      "fields": [
        {
          "name": "id",
          "type": "String",
          "optional": false,
          "attrs": "@id @default(cuid())",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "event",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "channel",
          "type": "String",
          "optional": false,
          "attrs": "",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "target",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "ok",
          "type": "Boolean",
          "optional": false,
          "attrs": "@default(false)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "attempts",
          "type": "Int",
          "optional": false,
          "attrs": "@default(1)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "error",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "durationMs",
          "type": "Int",
          "optional": false,
          "attrs": "@default(0)",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "title",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "body",
          "type": "String",
          "optional": false,
          "attrs": "@default(\"\")",
          "isRelation": false,
          "note": ""
        },
        {
          "name": "createdAt",
          "type": "DateTime",
          "optional": false,
          "attrs": "@default(now())",
          "isRelation": false,
          "note": ""
        }
      ],
      "fieldCount": 11
    }
  ],
  "pages": [
    {
      "path": "/",
      "file": "pages/index.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/:slug",
      "file": "pages/[slug].vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/about",
      "file": "pages/about.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/account",
      "file": "pages/account/index.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/account/security",
      "file": "pages/account/security.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/admin",
      "file": "pages/admin/index.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/account",
      "file": "pages/admin/account.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/backup",
      "file": "pages/admin/backup.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/engine-market",
      "file": "pages/admin/engine-market.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/engine-trust",
      "file": "pages/admin/engine-trust.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/engines",
      "file": "pages/admin/engines.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/forms",
      "file": "pages/admin/forms.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/home",
      "file": "pages/admin/home.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/login",
      "file": "pages/admin/login.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/media",
      "file": "pages/admin/media.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/members",
      "file": "pages/admin/members.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/admin/nav",
      "file": "pages/admin/nav.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/notify",
      "file": "pages/admin/notify.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/admin/operation-logs",
      "file": "pages/admin/operation-logs.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/pages",
      "file": "pages/admin/pages.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/performance",
      "file": "pages/admin/performance.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/reset",
      "file": "pages/admin/reset.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/roles",
      "file": "pages/admin/roles.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/seo",
      "file": "pages/admin/seo.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/site-config",
      "file": "pages/admin/site-config.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/site-texts",
      "file": "pages/admin/site-texts.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/admin/staff",
      "file": "pages/admin/staff.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/admin/themes",
      "file": "pages/admin/themes.vue",
      "isAdmin": true,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/co-develop",
      "file": "pages/co-develop.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/console",
      "file": "pages/console/index.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/console/demo",
      "file": "pages/console/demo.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/console/messages",
      "file": "pages/console/messages.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/contact",
      "file": "pages/contact.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/demo",
      "file": "pages/demo.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/developer",
      "file": "pages/developer.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/docs",
      "file": "pages/docs.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/faq",
      "file": "pages/faq.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/login",
      "file": "pages/login.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/privacy",
      "file": "pages/privacy.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/register",
      "file": "pages/register.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/reset-password",
      "file": "pages/reset-password.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/search",
      "file": "pages/search.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": true
    },
    {
      "path": "/systems",
      "file": "pages/systems/index.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/systems/:slug",
      "file": "pages/systems/[slug]/index.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/systems/:slug/changelog",
      "file": "pages/systems/[slug]/changelog.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/tag/:slug",
      "file": "pages/tag/[slug].vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    },
    {
      "path": "/tags",
      "file": "pages/tags.vue",
      "isAdmin": false,
      "hasSeo": true,
      "noindex": false
    }
  ],
  "components": [
    {
      "file": "components/admin/Alert.vue",
      "summary": ""
    },
    {
      "file": "components/admin/Badge.vue",
      "summary": ""
    },
    {
      "file": "components/admin/BlockEditor.vue",
      "summary": ""
    },
    {
      "file": "components/admin/Button.vue",
      "summary": ""
    },
    {
      "file": "components/admin/Card.vue",
      "summary": ""
    },
    {
      "file": "components/admin/Empty.vue",
      "summary": ""
    },
    {
      "file": "components/admin/EngineSettings.vue",
      "summary": ""
    },
    {
      "file": "components/admin/Field.vue",
      "summary": ""
    },
    {
      "file": "components/admin/ImageField.vue",
      "summary": ""
    },
    {
      "file": "components/admin/MediaPicker.vue",
      "summary": ""
    },
    {
      "file": "components/admin/Page.vue",
      "summary": ""
    },
    {
      "file": "components/admin/Pagination.vue",
      "summary": ""
    },
    {
      "file": "components/admin/Resource.vue",
      "summary": ""
    },
    {
      "file": "components/admin/Switch.vue",
      "summary": ""
    },
    {
      "file": "components/admin/Table.vue",
      "summary": ""
    },
    {
      "file": "components/AppFooter.vue",
      "summary": ""
    },
    {
      "file": "components/AppHeader.vue",
      "summary": ""
    },
    {
      "file": "components/AuthPanel.vue",
      "summary": ""
    },
    {
      "file": "components/BlockRenderer.vue",
      "summary": ""
    },
    {
      "file": "components/blocks/cta.vue",
      "summary": ""
    },
    {
      "file": "components/blocks/faqs.vue",
      "summary": ""
    },
    {
      "file": "components/blocks/features.vue",
      "summary": ""
    },
    {
      "file": "components/blocks/hero.vue",
      "summary": ""
    },
    {
      "file": "components/blocks/media.vue",
      "summary": ""
    },
    {
      "file": "components/blocks/products.vue",
      "summary": ""
    },
    {
      "file": "components/blocks/richtext.vue",
      "summary": ""
    },
    {
      "file": "components/blocks/stats.vue",
      "summary": ""
    },
    {
      "file": "components/BreadcrumbNav.vue",
      "summary": ""
    },
    {
      "file": "components/ConsoleShell.vue",
      "summary": ""
    },
    {
      "file": "components/engine/EnginePage.vue",
      "summary": ""
    },
    {
      "file": "components/FriendLinks.vue",
      "summary": ""
    },
    {
      "file": "components/HeroPanorama.vue",
      "summary": ""
    },
    {
      "file": "components/HeroSlideshow.vue",
      "summary": ""
    },
    {
      "file": "components/HomeIntro.vue",
      "summary": ""
    },
    {
      "file": "components/HomeSections.vue",
      "summary": ""
    },
    {
      "file": "components/IconBlock.vue",
      "summary": ""
    },
    {
      "file": "components/MarkdownView.vue",
      "summary": ""
    },
    {
      "file": "components/MemberBenefits.vue",
      "summary": ""
    },
    {
      "file": "components/PageHero.vue",
      "summary": ""
    },
    {
      "file": "components/SceneTabs.vue",
      "summary": ""
    },
    {
      "file": "components/SiteActionBar.vue",
      "summary": ""
    },
    {
      "file": "components/SiteHeader.vue",
      "summary": ""
    },
    {
      "file": "components/SiteLogo.vue",
      "summary": ""
    },
    {
      "file": "components/SystemThumb.vue",
      "summary": ""
    },
    {
      "file": "components/TemplateSection.vue",
      "summary": ""
    },
    {
      "file": "components/TemplateSlots.vue",
      "summary": ""
    }
  ],
  "composables": [
    {
      "file": "composables/block-registry.ts",
      "summary": "",
      "functions": [
        "registerEngineBlockDefs",
        "allBlockDefs",
        "blockDef",
        "isEngineBlockDef"
      ],
      "exports": [
        "BlockFieldDef",
        "BlockTypeDef",
        "BLOCK_DEFS"
      ]
    },
    {
      "file": "composables/content-tokens.ts",
      "summary": "内容占位符 / 片段 **唯一注册表**（2026-10-07 · P2-7 · 站主 ②） 站主原话：「页面内容升级为 CMS 全功能，可自定义页面内容，并可**生成自定义引用的标签给主题调用**」✓。",
      "functions": [
        "renderContentTokens",
        "renderTokensDeep"
      ],
      "exports": [
        "ContentTokenContext",
        "ContentTokenDef",
        "CONTENT_TOKENS",
        "CONTENT_TOKEN_RE"
      ]
    },
    {
      "file": "composables/csv.ts",
      "summary": "CSV 生成（纯函数 ✓ 可单测 ✓）—— 2026-10-06 · P2-10 【为什么单独一处】后台的\"导出\"正在从一条变成多条（线索 ✓、会员 ✓，以后还会有别的 ✓）。",
      "functions": [
        "csvCell",
        "csvSafe",
        "csvRow",
        "csvText"
      ],
      "exports": []
    },
    {
      "file": "composables/dev-guide.ts",
      "summary": "开发者中心的「作者指南」内容（2026-10-06） 【为什么是数据、不是页面上的一堆模板】`docs/ecosystem-plan.md` §问题 4 的诊断是：",
      "functions": [
        "useDevGuide"
      ],
      "exports": [
        "GuideStep",
        "GuideChapter",
        "DEV_GUIDE",
        "DEV_GUIDE_NOTE"
      ]
    },
    {
      "file": "composables/error-content.ts",
      "summary": "404 / 500 错误页的内容（可配）—— 2026-10-07 · SEO 程序第 4 项 【为什么要可配】错误页不光给访客\"出路\" ✓，也是搜索引擎判定\"这个站有没有用\"的地方之一 ✓",
      "functions": [
        "safeLinkTarget",
        "parseErrorContent"
      ],
      "exports": [
        "ERROR_CONTENT_KEY",
        "ErrorContentLink",
        "ErrorContent",
        "MAX_ERROR_LINKS",
        "DEFAULT_ERROR_CONTENT"
      ]
    },
    {
      "file": "composables/friend-links.ts",
      "summary": "友情链接（2026-10-07 · SEO 第 2 项）—— 作用域注册表 + 规范化（**纯函数** ✓ 可单测 ✓） ## 站主要什么",
      "functions": [
        "scopeOfPath",
        "isSafeLinkUrl",
        "normalizeFriendLinks",
        "groupByScope"
      ],
      "exports": [
        "FriendLinkScopeDef",
        "FRIEND_LINK_SCOPES",
        "FRIEND_LINK_DEFAULT_SCOPE",
        "FriendLink",
        "FRIEND_LINK_LIMITS"
      ]
    },
    {
      "file": "composables/media-types.ts",
      "summary": "媒体类型白名单（**唯一真源**，前后端共用） 【为什么放在 composables/ 而不是 server/utils/】",
      "functions": [
        "extOf",
        "mediaTypeOfName",
        "deniedReason",
        "mimeOfName",
        "mediaKindOfMime",
        "mimesOfKind"
      ],
      "exports": [
        "MediaKind",
        "MediaTypeDef",
        "MEDIA_TYPES",
        "MEDIA_DENIED",
        "MEDIA_KIND_LABEL",
        "MEDIA_ACCEPT_ATTR"
      ]
    },
    {
      "file": "composables/search-pinyin.generated.ts",
      "summary": "站内搜索用的「汉字 → 拼音首字母」映射 —— **自动生成，请勿手改**。 生成器：scripts/gen-search-pinyin.mjs（构建期跑，需要 pinyin-pro 这个 devDependency）。",
      "functions": [
        "pinyinInitials"
      ],
      "exports": [
        "SEARCH_PINYIN_INITIAL"
      ]
    },
    {
      "file": "composables/source-label.ts",
      "summary": "「扩展从哪来」的中文标签（**唯一一处**） 数据源：`EnginePackage.installedFrom` —— 由安装路径写入：",
      "functions": [
        "sourceLabel"
      ],
      "exports": []
    },
    {
      "file": "composables/text-registry.ts",
      "summary": "",
      "functions": [],
      "exports": [
        "TextDef",
        "TEXT_DEFS"
      ]
    },
    {
      "file": "composables/useAuth.ts",
      "summary": "",
      "functions": [],
      "exports": [
        "useAuth"
      ]
    },
    {
      "file": "composables/useCsrf.ts",
      "summary": "",
      "functions": [
        "useCsrfHeader"
      ],
      "exports": []
    },
    {
      "file": "composables/useEngineSettings.ts",
      "summary": "读某个扩展（主题 / 区块 / 模块）在后台配置的**公开设置**，可选按页面覆盖（基座 M2） 【为什么主题参数走运行时而不是构建期】主题的结构（布局、页面、样式）天生是构建期确定的，",
      "functions": [],
      "exports": []
    },
    {
      "file": "composables/useFormDraft.ts",
      "summary": "",
      "functions": [
        "useFormDraft"
      ],
      "exports": []
    },
    {
      "file": "composables/useMember.ts",
      "summary": "",
      "functions": [
        "useMember"
      ],
      "exports": []
    },
    {
      "file": "composables/useSeo.ts",
      "summary": "",
      "functions": [
        "useSeoConfigState",
        "useSeo"
      ],
      "exports": [
        "SeoBreadcrumb",
        "SeoPageConfig",
        "SeoVerifyMeta",
        "SeoConfigState",
        "UseSeoOptions"
      ]
    },
    {
      "file": "composables/useSiteContent.ts",
      "summary": "站内内容的统一读取入口 —— **基座对外内容契约**（主题与核心页面共用） 【它解决什么】主题（尤其由 HTML 模板改来的）要展示站内内容时，不该去记",
      "functions": [
        "normalizeSiteContent",
        "mergeSettings"
      ],
      "exports": [
        "ENGINE_CONTRACT_VERSION",
        "SiteContentKind",
        "NavScope",
        "SiteContentOptions",
        "ContractProduct",
        "ContractFaq",
        "ContractPage",
        "ContractChangelog",
        "ContractNavItem",
        "ContractNav"
      ]
    },
    {
      "file": "composables/useSiteSearch.ts",
      "summary": "",
      "functions": [
        "tokenize",
        "useSiteSearch"
      ],
      "exports": [
        "SearchItem",
        "HighlightSeg",
        "SearchGroup"
      ]
    },
    {
      "file": "composables/useSiteTexts.ts",
      "summary": "",
      "functions": [
        "useSiteTexts"
      ],
      "exports": []
    }
  ],
  "clientPlugins": [
    {
      "file": "plugins/engine-ui.ts",
      "summary": ""
    },
    {
      "file": "plugins/pinia-payload-guard.ts",
      "summary": ""
    },
    {
      "file": "plugins/reveal.client.ts",
      "summary": "滚动入场动效（克制、非循环） 设计要点（性能与稳健性）："
    },
    {
      "file": "plugins/seo-config.ts",
      "summary": "预取后台 SEO 配置 为什么要用插件而不是在 useSeo 里直接 useFetch："
    },
    {
      "file": "plugins/web-vitals.client.ts",
      "summary": ""
    }
  ],
  "layouts": [
    {
      "file": "layouts/admin.vue",
      "summary": ""
    },
    {
      "file": "layouts/auth.vue",
      "summary": ""
    },
    {
      "file": "layouts/default.vue",
      "summary": ""
    }
  ],
  "routeMiddleware": [
    {
      "file": "middleware/admin.ts",
      "summary": ""
    }
  ],
  "tests": [
    {
      "file": "tests/admin/csv.test.ts",
      "summary": ""
    },
    {
      "file": "tests/admin/dashboard-p16.test.ts",
      "summary": ""
    },
    {
      "file": "tests/admin/media-types.test.ts",
      "summary": ""
    },
    {
      "file": "tests/admin/metrics.test.ts",
      "summary": ""
    },
    {
      "file": "tests/admin/nav-groups.test.ts",
      "summary": ""
    },
    {
      "file": "tests/admin/notify-templates.test.ts",
      "summary": ""
    },
    {
      "file": "tests/admin/permissions-p15.test.ts",
      "summary": ""
    },
    {
      "file": "tests/admin/sidebar.test.ts",
      "summary": ""
    },
    {
      "file": "tests/admin/site-config-p14.test.ts",
      "summary": ""
    },
    {
      "file": "tests/admin/staff.test.ts",
      "summary": ""
    },
    {
      "file": "tests/api-changelog.test.ts",
      "summary": ""
    },
    {
      "file": "tests/api-error.test.ts",
      "summary": ""
    },
    {
      "file": "tests/backup/database.test.ts",
      "summary": "备份模块的\"清单与形状\"单测（2026-10-07 · P1） 这里不做真实读写（那属于端到端探针 ✓），只钉住**会静默出错**的那几件事："
    },
    {
      "file": "tests/backup/store.test.ts",
      "summary": "备份存放层的边界（2026-10-07 · P1） 钉住两件事："
    },
    {
      "file": "tests/backup/tar.test.ts",
      "summary": "流式 tar 打包/解包（2026-10-07 · P1）的单测 这里盯的是**最容易被改坏的三件事** ✓："
    },
    {
      "file": "tests/content-cache.test.ts",
      "summary": ""
    },
    {
      "file": "tests/content-tokens.test.ts",
      "summary": ""
    },
    {
      "file": "tests/csp.test.ts",
      "summary": ""
    },
    {
      "file": "tests/csrf.test.ts",
      "summary": ""
    },
    {
      "file": "tests/dev-guide.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/auto-import-contract.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/build-gc.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/build-inventory.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/distribution.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/graph.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/hooks.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/hosts.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/install-response-shape.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/license.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/manifest-blocks.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/manifest.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/perm-match.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/perm-table.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/pure-frontend.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/region-contract.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/routes.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/scan.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/settings.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/submission-review.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/surface.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/theme-contract.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/theme-seo.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/theme-validate.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/theme.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/trust.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/ui-inventory.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/ui-shim-names.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/ui-table.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine/ui-usable.test.ts",
      "summary": ""
    },
    {
      "file": "tests/engine-contract.test.ts",
      "summary": ""
    },
    {
      "file": "tests/error-content.test.ts",
      "summary": ""
    },
    {
      "file": "tests/forms.test.ts",
      "summary": ""
    },
    {
      "file": "tests/permissions.test.ts",
      "summary": ""
    },
    {
      "file": "tests/push-paths.test.ts",
      "summary": ""
    },
    {
      "file": "tests/push-plan.test.ts",
      "summary": ""
    },
    {
      "file": "tests/push-quota.test.ts",
      "summary": ""
    },
    {
      "file": "tests/route-perms.test.ts",
      "summary": ""
    },
    {
      "file": "tests/seo-verify.test.ts",
      "summary": ""
    },
    {
      "file": "tests/site-config-registry.test.ts",
      "summary": ""
    },
    {
      "file": "tests/text-registry.test.ts",
      "summary": ""
    }
  ],
  "scripts": [
    {
      "file": "scripts/engine-e2e.mjs",
      "summary": "引擎端到端验收脚本（本地跑，需要 dev server + 数据库） 用途：验证「装 / 更新 / 停用扩展都不需要重新构建、也不需要重启」这条链。"
    },
    {
      "file": "scripts/gate-compile.mjs",
      "summary": ""
    },
    {
      "file": "scripts/gate-typecheck.mjs",
      "summary": ""
    },
    {
      "file": "scripts/gen-search-pinyin.mjs",
      "summary": "生成站内搜索用的「汉字 → 拼音首字母」映射（构建期，产物是一份小常量表）。 【为什么不在客户端引拼音库】pinyin-pro 完整包是几百 KB 的数据表，为了\"输入 jz 能搜到建站\""
    },
    {
      "file": "scripts/generate-dev-docs.mjs",
      "summary": "生成开发文档数据 public/dev-docs.json 为什么是生成的而不是手写：接口清单、数据模型、组件与组合式函数这几块"
    },
    {
      "file": "scripts/generate-og-image.mjs",
      "summary": "生成全站默认分享图 public/og-cover.png（1200×630） 为什么要有这个脚本而不是直接扔一张图进仓库："
    },
    {
      "file": "scripts/site-audit.mjs",
      "summary": ""
    },
    {
      "file": "scripts/theme-import.mjs",
      "summary": "把静态 HTML 模板导入成禾君主题骨架 【为什么是一个脚本，而不是手抄】Moderncommerce 有 18 个页面、首页 1563 行、24MB 资源。"
    },
    {
      "file": "scripts/theme-switch.mjs",
      "summary": "切主题 + 重启 + 核实（把踩过的坑固化成一个可靠动作） 用法："
    }
  ],
  "envGroups": [
    {
      "group": "数据库",
      "items": [
        {
          "kind": "var",
          "key": "DATABASE_URL",
          "defaultValue": "postgresql://hejun:CHANGE_ME_STRONG_PASSWORD@localhost:5432/hejun_website?schema=public"
        }
      ]
    },
    {
      "group": "Redis（页面缓存 + 临时演示账号会话）",
      "items": [
        {
          "kind": "var",
          "key": "REDIS_URL",
          "defaultValue": "redis://localhost:6379"
        }
      ]
    },
    {
      "group": "JWT 会话（后台登录令牌，生产环境务必替换为强随机值）",
      "items": [
        {
          "kind": "var",
          "key": "NUXT_JWT_SECRET",
          "defaultValue": "change-me-to-a-long-random-secret"
        },
        {
          "kind": "var",
          "key": "NUXT_JWT_EXPIRES_IN",
          "defaultValue": "7d"
        },
        {
          "kind": "var",
          "key": "NUXT_BCRYPT_ROUNDS",
          "defaultValue": "12"
        }
      ]
    },
    {
      "group": "站点公开信息",
      "items": [
        {
          "kind": "comment",
          "text": "⚠️ 生产必须改成正式域名：canonical / og:url / sitemap.xml / robots.txt 全部以它为准。"
        },
        {
          "kind": "comment",
          "text": "配错（例如留成 localhost 或预发域名）会把错误地址提交给搜索引擎，属于\"自己挖坑\"。"
        },
        {
          "kind": "var",
          "key": "NUXT_PUBLIC_SITE_URL",
          "defaultValue": "https://www.hejun1.com"
        }
      ],
      "note": "⚠️ 生产必须改成正式域名：canonical / og:url / sitemap.xml / robots.txt 全部以它为准。"
    },
    {
      "group": "SEO 站长平台验证（可选）",
      "items": [
        {
          "kind": "comment",
          "text": "也可以直接在后台「SEO 设置」里填，那边优先级更高、改完即时生效；"
        },
        {
          "kind": "comment",
          "text": "这里的变量适合部署时由 CI 注入、不想让人在界面上看到的场景。"
        },
        {
          "kind": "var",
          "key": "NUXT_PUBLIC_GOOGLE_SITE_VERIFICATION",
          "defaultValue": ""
        },
        {
          "kind": "var",
          "key": "NUXT_PUBLIC_BING_SITE_VERIFICATION",
          "defaultValue": ""
        },
        {
          "kind": "var",
          "key": "NUXT_PUBLIC_BAIDU_SITE_VERIFICATION",
          "defaultValue": ""
        }
      ],
      "note": "也可以直接在后台「SEO 设置」里填，那边优先级更高、改完即时生效；"
    },
    {
      "group": "搜索引擎主动推送",
      "items": [
        {
          "kind": "comment",
          "text": "百度普通收录 token 与 IndexNow key 都只在后台「SEO 设置」里填，"
        },
        {
          "kind": "comment",
          "text": "存进数据库的 secret_ 前缀键（不会被公开接口下发），因此这里没有对应变量。"
        }
      ],
      "note": "百度普通收录 token 与 IndexNow key 都只在后台「SEO 设置」里填，"
    },
    {
      "group": "消息推送 Webhook（企微 / 飞书），enabled 控制总开关",
      "items": [
        {
          "kind": "var",
          "key": "NUXT_WEBHOOK_WECOM",
          "defaultValue": ""
        },
        {
          "kind": "var",
          "key": "NUXT_WEBHOOK_FEISHU",
          "defaultValue": ""
        },
        {
          "kind": "var",
          "key": "NUXT_WEBHOOK_ENABLED",
          "defaultValue": "false"
        }
      ]
    },
    {
      "group": "邮件通知（Nodemailer）",
      "items": [
        {
          "kind": "var",
          "key": "NUXT_MAIL_HOST",
          "defaultValue": ""
        },
        {
          "kind": "var",
          "key": "NUXT_MAIL_PORT",
          "defaultValue": "465"
        },
        {
          "kind": "var",
          "key": "NUXT_MAIL_SECURE",
          "defaultValue": "true"
        },
        {
          "kind": "var",
          "key": "NUXT_MAIL_USER",
          "defaultValue": ""
        },
        {
          "kind": "var",
          "key": "NUXT_MAIL_PASS",
          "defaultValue": ""
        },
        {
          "kind": "var",
          "key": "NUXT_MAIL_FROM",
          "defaultValue": ""
        }
      ]
    },
    {
      "group": "临时演示账号有效期（小时）",
      "items": [
        {
          "kind": "var",
          "key": "NUXT_DEMO_ACCOUNT_EXPIRE_HOURS",
          "defaultValue": "24"
        }
      ]
    },
    {
      "group": "初始管理员账号（prisma/seed.ts / 巡检 scripts/site-audit.mjs 共用）",
      "items": [
        {
          "kind": "comment",
          "text": "⚠️ 改名或改密码时**三处必须一起改**：这里、prisma/seed.ts（读同一对变量）、数据库里那一行。"
        },
        {
          "kind": "comment",
          "text": "原因：seed 用的是 `upsert({ where: { username } })` —— 若这里的用户名与库里不一致，"
        },
        {
          "kind": "comment",
          "text": "下次 `npm run db:seed` 会走 create 分支，凭空**新建一个默认密码的旧账号**。"
        },
        {
          "kind": "comment",
          "text": "不配则回落到 seed.ts 里的默认值。"
        },
        {
          "kind": "var",
          "key": "SEED_ADMIN_USERNAME",
          "defaultValue": "chaos"
        },
        {
          "kind": "var",
          "key": "SEED_ADMIN_PASSWORD",
          "defaultValue": "change-me"
        }
      ],
      "note": "⚠️ 改名或改密码时**三处必须一起改**：这里、prisma/seed.ts（读同一对变量）、数据库里那一行。"
    }
  ],
  "stats": {
    "apiCount": 128,
    "adminApiCount": 95,
    "modelCount": 27,
    "pageCount": 47,
    "componentCount": 46,
    "composableCount": 19,
    "enginePackageCount": 9,
    "engineHookCount": 4,
    "enginePlannedHookCount": 0
  }
}