Files
bigcode 62e6bcfcd2 v0.14.0 设置页 Tabs 表单+登录安全(reCAPTCHA/锁定);TipTap 富文本编辑器(Markdown/媒体库);前台移动端自适应
- /admin/settings 弃用 JSON 编辑器改 antd Tabs 分组表单(site/woocommerce/mail/seo/security),未知键落「其他」JSON 兜底
- 登录安全:reCAPTCHA v2/v3 开关+密钥+阈值(siteverify fail closed),失败次数锁定;/admin 与 /my-account 登录接入
- 内容正文与产品详细描述换 TipTap v3:工具栏/Markdown 输入与导入/HTML 源码/图片上传/媒体库选图
- 根路由补 viewport meta(移动端根因);390px 实测 14 关键页 0 横向溢出
- 首页 Advance Tabs ≤767px 横滑、联系页内联 margin 块收缩、/shop 网格 4→3→2 列、移动菜单手风琴
2026-11-04 14:08:49 +08:00

125 lines
9.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 后台(Admin / CRM)与 MCP 说明
> v0.14.0 起:设置页 Tabs 表单 + 登录安全(reCAPTCHA/失败锁定)、TipTap 富文本编辑器(Markdown/媒体库)、前台移动端自适应(viewport + 溢出收敛)。
> v0.13.0 起:前台导航修复(loader 服务函数化)、全站图片占位图 + 懒加载、favicon。
> v0.12.0 起:PG 16 → 18.6(增量备份能力)、备份系统(全量/增量/S3)、用户权限分层。
> v0.11.0 起:后台按「功能接近原版 WordPress + 现代化 CRM 界面」重做一轮,并新增站点管理 MCP 服务器。
## 系统设置与登录安全(v0.14.0)
- `/admin/settings` 弃用整键 JSON 编辑器,改为 **antd Tabs 分组表单**:站点信息 / 商城配置 /
邮件配置 / SEO / **登录安全**;保存时与现有 JSON 合并(表单未覆盖的字段保留)。
无表单定义的键(backup 等专属页管理的除外)落在「其他」Tab 仍以 JSON 编辑兜底。
- **登录安全**(settings 表 key=security,`src/server/security.ts`):
- reCAPTCHA 开关 + 版本(v2 复选框 / v3 隐形评分)+ Site/Secret Key + v3 阈值;
开启后 `/admin` 与 `/my-account` 登录均需通过 Google siteverify(6s 超时,fail closed),
前端组件 `src/components/admin/Recaptcha.tsx`(未开启不注入 Google 脚本)。
- 登录失败锁定:同邮箱连续失败 ≥ 上限(默认 10)锁定(默认 15 分钟);进程内存计数,重启清零。
- 公开配置经 `getLoginSecurityPublic` 下发(仅 enabled/version/siteKey,Secret 不回传)。
## 富文本编辑器(v0.14.0)
- 内容编辑页(正文)与产品编辑页(详细描述)换 **TipTap v3**(`src/components/admin/RichEditor.tsx`):
- 工具栏:撤销重做 / 标题 H2-H4 / 加粗斜体下划线删除线行内代码 / 列表 / 引用 / 分隔线 /
代码块 / 链接 / 图片 / 表格 / 清除格式 / HTML 源码切换;
- **Markdown**:输入即时转换(`## `→H2、`**`加粗、`-` 列表等 input rules)+「Markdown 导入」
弹窗(marked 解析,可插入光标处或替换正文);
- **媒体库**:图片按钮本地上传(`uploadMediaFile` → /uploads/YYYY/MM/)或「媒体库选图」弹窗
(`MediaPickerModal`,搜索/分页/缩略图);
- antd Form 受控(value/onChange),SSR 需 `immediatelyRender: false`(已内置)。
- 编辑器样式 `src/styles/admin-editor.css`(仅 `.rich-editor` 作用域,随组件 import)。
## 前台移动端自适应(v0.14.0)
- **根路由补 `<meta name="viewport">`**——此前缺失导致手机按 ~980px 布局再缩小,是「移动端没有」的根因。
- 溢出收敛(390px 实测 14 个关键页全部 0 横向溢出,`scripts` 外的诊断脚本见 /tmp):
- 首页 Elementor Advance Tabs 横向标签条 ≤767px 改横滑(`min-width: max-content` + overflow-x);
- 内容模板 `width:100%`+左 margin 的内联信息块(联系页地址等)≤767px 收缩为自适应;
- /shop/ 产品网格 4→3(≤1024)→2(≤767)列;
- `content-html iframe` max-width 100%。
- Header 移动端菜单改**手风琴**(顶级项可跳转 + 箭头展开子菜单,默认收起)。
## 前台约定(v0.13.0 起生效)
- **TanStack Start loader 是同构运行的**:客户端导航(点击 LOGO / `<Link>` / 分页)会在浏览器重跑一遍
loader。凡直接调用 `db`/查询层的写法(依赖 `bun:sql`,客户端是 stub)全部失败,页面退化为空数据。
**loader 的数据获取必须走 `createServerFn`**(服务端执行返回纯 JSON);`redirect()/notFound()` 不能在
serverFn 内抛给 Router,用协议标记(如 `$.tsx` 的 `__redirect/__notFound`)回传后由 loader 本地抛出。
已改造:`loadHomePage`(/)、`loadCatchAll`(/$)、`loadProduct`、`loadCollectionCategory`、`loadShopData`、
`loadSearchData`、`loadContactData`、`loadBlogPost`、`loadSolutionPage`、`loadBlogArchive`、`loadSolutionArchive`、
`loadCollection`(/collection/)等;购物车/结账/账户本来就用 serverFn(getCart/getCurrentUser/getMyOrders)。
- **图片占位图与懒加载**:`public/uploads/placeholder.jpg`(灰底 + 低透明度 LOGO,300×260,ImageMagick 生成);
全部前台 `<img>` 由 Layout 内联脚本补 `loading="lazy" decoding="async"`(MutationObserver 覆盖新增节点),
加载完成前显示占位背景(`app.css` 的 `.ds-site img` 规则;作用域为 Layout 的 `<main class="ds-site">`)。
注意透明 PNG 加载完成后会透出占位图——导出透明图时慎用。
- **缺失图片补齐**:`bun run scripts/sync-missing-uploads.ts` 幂等——扫库(contents/products/media)引用路径,
与 public/uploads 比对,缺失文件从原站下载(v0.13.0 补回 90 张;原站已失效 38 张不可恢复,走占位图)。
- **favicon**:`public/favicon.ico`(原站 32×32 PNG 转 ICO,ImageMagick)+ `apple-touch-icon.png`(LOGO 180×180),
根路由 `head().links` 注入。
- **导航宽度**:Header 顶栏与主导航行统一 `max-w-[1400px] mx-auto` 居中(2026-11-04 用户指定,原站基准)。
## 用户权限分层(RBAC)
两类用户:**普通用户**(customer,仅商城账号)与**后台用户**(admin > manager > editor)。能力矩阵(`src/server/auth.ts` requireCapability):
| 能力域 | 允许角色 | 覆盖操作 |
| --- | --- | --- |
| content | admin/manager/editor | 内容保存/删除、修订恢复、媒体上传/编辑、菜单项、筛选、重定向 |
| commerce | admin/manager | 产品保存/删除、订单状态、询盘状态 |
| system | admin | 用户管理、系统设置、语言、备份、审计日志查看 |
用户页 `/admin/users/` 提供「全部 / 后台用户 / 普通用户」Tab。
## 备份系统(PostgreSQL 18 物理备份)
- PG 已升级 **16.15 → 18.6**(容器 `dusuniot-pg`,`summarize_wal=on`,命名卷 `dusuniot-pg18-data`,`--restart unless-stopped`;旧 16 容器保留为 `dusuniot-pg16-old` 可回滚)
- 全量:`pg_basebackup -Fp -Xs` → `backups/pg/full-<ts>/`
- 增量:`pg_basebackup --incremental=<最近备份>/backup_manifest`(PG 17+ 能力;实测全量 124MB → 增量 5.4MB)
- 归档:每次备份 tar.gz → `backups/artifacts/`;配置 S3 后上传(Bun.S3Client,支持 multipart 大文件)
- 保留:保留最近 N 个全量链(该全量及其后全部增量),本地与 S3 同步清理
- 恢复:`pg_combinebackup 全量 增量…` 合并 → 作为 PGDATA 启动(已在容器内实测恢复 699 内容完整)
- 定时:settings.backup.schedule 开启后,jobs worker(`bun scripts/jobs-worker.ts`)按间隔执行 `backup.run`(自动增量、无备份时全量),完成后自排下一轮
- UI:`/admin/backups`(仅 admin):立即全量/增量、本地+S3 列表、删除、S3/保留/定时配置
## 后台功能清单(/admin,React + Ant Design)
| 模块 | 路由 | 能力 |
| --- | --- | --- |
| Dashboard | `/admin/` | KPI 卡(30 天环比:订单/营收/新询盘)、近 30 天订单/询盘/营收三趋势图、询盘漏斗(new/read/replied/spam/archived 占比)、最近订单 + 最新询盘、快捷入口 |
| 页面 / 文章 | `/admin/contents/` | page/post/landing Tab、搜索、分页、删除;编辑页支持 **分类目录/标签绑定**(content_terms)、**Elementor JSON** 编辑(meta.elementor,前台 `/slug/` 通栏渲染)、**修订历史**(保存自动留档、查看/恢复)、已发布页面前台预览链接 |
| 菜单 | `/admin/menus/` | menus 4 个位置(menu-1/menu-2/max_mega_menu_1/max_mega_menu_2)+ menu_items 树编辑(父级/排序/新窗口),前台 Header/Footer 即时读取 |
| 媒体库 | `/admin/media/` | 列表/搜索/预览、alt 与标题编辑、**上传**(≤20MB,写入 uploads/YYYY/MM/,自动解析 PNG/JPEG/GIF/WebP 宽高) |
| 产品 | `/admin/products/` | CRUD + 属性/分类/特色图/图集 |
| 订单 | `/admin/orders/` | 列表/详情/状态流转 |
| 询盘 | `/admin/inquiries/` | 状态 Tab、关键字、详情抽屉、跟进流转(new→read→replied) |
| 语言 | `/admin/languages/` | 启用开关 |
| SEO / 重定向 | `/admin/seo/` | 重定向 CRUD(301/302/正则) |
| 筛选 | `/admin/filters/` | 前台产品筛选器配置 |
| 用户 | `/admin/users/` | 列表/搜索;admin 可新建用户、改角色、重置密码(最后一个 admin 防降级锁死) |
| 系统设置 | `/admin/settings/` | settings 表 kv JSON 编辑器(site/woocommerce/mail/seo),仅 admin 可保存 |
| 审计日志 | `/admin/audit/` | 全部后台写操作留痕(操作人/动作/实体/摘要),含 MCP 调用(actor 为空) |
规范:所有 server function 第一步 `requireAdmin()`;写操作落 `audit_logs`;图标全 SVG(lucide / antd icons)。
## MCP 服务器(dusuniot-cms)
- 入口:`mcp/server.ts`(Bun 直跑,stdio JSON-RPC,MCP 2024-11-05,无 SDK 依赖)
- 注册:`.zcode/config.json`(workspace 级,会话启动自动连接)
- 直连 PostgreSQL(`DATABASE_URL`,默认 `postgres://dusuniot:dusuniot@127.0.0.1:25432/dusuniot`),仅限受信任本机;写操作落审计日志(actor 为空 = MCP)
- 工具(17 个):
- `dashboard_stats` 看板统计
- `list_contents` / `get_content` / `create_content` / `update_content` / `delete_content`(自定义单页面:type=page + elementorJson,保存/更新自动留修订快照,slug 冲突自动加后缀)
- `list_revisions` / `restore_revision`
- `list_media` / `upload_media`(base64,≤20MB,自动解析宽高)
- `list_products` / `list_orders` / `update_order_status`
- `list_inquiries` / `update_inquiry_status`
- `get_setting` / `set_setting`
## 手动测试
```sh
bun mcp/server.ts # stdio;initialize → tools/list → tools/call
bun test # 11 pass
bun run build && bun scripts/prod-server.ts # 站点 + 后台 :3312
```