Appearance
静态博客与提示词管理后台重构设计
日期:2026-09-22 适用工作树:codex/blog-backend-admin
1. 背景与目标
现有实现把个人 VitePress 静态博客扩展成了数据库驱动 CMS:文章、分类、标签、站点配置、GitHub 项目、媒体、发布快照和导出都在后台形成了第二份数据源。这与项目实际维护方式不符,也产生了数据库到 Markdown/JSON 的同步、发布和回滚复杂度。
本次重构采用与主流静态内容站一致的核心模式:Markdown、JSON 和静态资源是公开博客的唯一内容源,VitePress 在构建阶段生成页面,线上不通过 Spring Boot 实时读取文章正文。
后台不再承担博客 CMS 职责。后台改为最小的 React + Spring Boot 管理系统,保留单管理员认证、MySQL 和 MinIO,并在本轮实现私有的“提示词 + 一张生成图片”上传管理功能。
2. 总体架构
2.1 公开博客
text
Markdown / JSON / docs/public 资源
↓
VitePress 与现有构建脚本
↓
静态 HTML / CSS / JavaScript
↓
现有静态发布流程公开博客不依赖 Spring Boot 获取文章、分类、标签、站点配置或 GitHub 项目数据。版本历史和回滚由 Git 负责。
2.2 管理系统
text
React 管理前端
↓ 同源 /api
Spring Boot 最小后端
├── 单管理员认证与会话 → MySQL
├── 提示词元数据 → MySQL
└── 提示词生成图片 → MinIO 私有桶管理系统与公开博客之间不设置发布快照、数据库导出、自动部署或回滚链路。本轮上传的提示词记录仅在登录后的管理后台可见。
3. 保留范围
3.1 静态博客
- 现有 VitePress 页面、Markdown、JSON 和
docs/public资源。 - 搜索索引、RSS、飞书同步、GitHub 项目更新和图片处理脚本。
docs/public/github-projects.json及npm run add-github-project。- 当前静态提示词档案及其公开页面,不迁移到新后台。
3.2 后端
- Spring Boot 工程骨架。
- 单管理员登录、退出、本人修改密码。
- 会话验证、CSRF、BCrypt 密码哈希和登录失败锁定。
- 统一 API 响应、安全异常处理和必要基础配置。
- MySQL、MinIO 连接和 Docker 编排。
- 新增提示词上传管理 API。
3.3 管理前端
- 管理前端继续保留,但从 Vue/Element Plus 重建为 React。
- 技术栈:React、TypeScript、Vite、React Router、Axios、Ant Design。
- 不引入 Redux;登录状态使用轻量 Context 或等价最小方案。
- 页面包括登录、提示词列表、新建、详情和本人修改密码。
4. 删除范围
4.1 业务功能
- 数据库版文章管理、草稿、发布、归档和修订历史。
- 分类管理与标签管理。
- 站点配置管理。
- GitHub 项目后台管理。
- Dashboard。
- 文章媒体库与原通用上传业务。
- 发布快照、文章公开版本、后台数据导出。
- 后台自动部署、发布队列和回滚规划。
- 多管理员列表、创建、启用、禁用和代重置密码。
- 数据库业务操作日志。
4.2 代码和文档
- 上述业务对应的 Controller、Service、Repository、Mapper、请求/响应模型和测试。
- 现有 Vue 页面、路由、状态代码和 Element Plus 依赖。
scripts/export-backend-snapshot.mjs及专用测试。- 旧 CMS 阶段报告、完成报告和 Vue 开发计划。
- 与废弃 CMS 业务相关的数据库迁移和表。
MinIO 容器、存储卷和已有对象不得删除。
5. 认证设计
5.1 保留能力
- 单管理员登录与退出。
- 当前管理员修改本人密码。
- BCrypt 密码哈希。
- 服务端会话。
- CSRF 防护。
- 登录失败阈值与临时锁定。
- 修改密码后使旧认证状态失效或要求重新登录。
5.2 删除能力
- 多管理员管理 API。
- 管理员角色、权限组和复杂 RBAC。
- 数据库业务审计日志。
首个管理员通过安全的本地环境配置引导创建。前端不得把密码或长期认证令牌保存到 localStorage。
6. 提示词管理数据模型
一条提示词严格对应一张生成图片。记录创建后不可编辑;上传错误时永久删除并重新创建。
提示词记录包含:
id:UUID。prompt_text:提示词正文,使用长文本类型。prompt_hash:规范化提示词的稳定哈希,唯一。object_key:MinIO 私有对象键。mime_type:从真实文件内容识别的格式。width、height:图片像素尺寸。file_size:字节数。image_sha256:图片内容哈希,仅记录,不设置唯一约束。delete_state:用于可重试永久删除流程。created_at:创建时间。
不保存以下字段:
- 来源链接与来源标题。
- 提示词标题。
- 生成模型。
- 用户手工填写的尺寸或质量。
- 签名预览 URL。
7. 提示词与图片规则
7.1 提示词
- 去除首尾空白后不能为空。
- 最大 50,000 个字符。
- 保留正文内部换行和空白。
- 规范化仅包括统一换行为
\n并去除首尾空白;不得折叠或改写正文内部空白。 - 对规范化后的完整正文计算哈希。
- 完全相同的提示词禁止重复创建,返回 HTTP
409。
7.2 图片
- 每次只上传一张图片,不支持批量上传。
- 允许 PNG、JPEG 和 WebP。
- 根据文件头和解码结果识别真实格式,不信任文件扩展名。
- 单张最大 10 MB。
- 宽度和高度分别不超过 8192 像素。
- 总像素不超过 4000 万。
- 不自动压缩或改写原图。
- 同一图片允许用于不同提示词;图片哈希不参与去重。
8. MinIO 设计
- 使用专用私有桶
prompt-results。 - 禁止匿名访问。
- 对象键由后端生成,不使用用户原始文件名作为路径。
- 后台预览由后端生成 15 分钟有效的签名 URL。
- 签名 URL 不写入数据库。
- 现有 MinIO 卷和对象保持不动。
9. API 设计
所有提示词接口仅允许已登录管理员访问,并要求写请求通过 CSRF 校验。
POST /api/admin/prompts:multipart 创建一条提示词并上传一张图片。GET /api/admin/prompts:分页列表,支持提示词关键词搜索。GET /api/admin/prompts/{id}:查看完整记录及临时预览地址。DELETE /api/admin/prompts/{id}:永久删除记录与 MinIO 图片。
列表规则:
- 服务端分页。
- 默认每页 20 条,可选择每页 50 条。
- 按创建时间倒序。
- 搜索使用 MySQL 简单正文模糊匹配。
- 不支持分类、标签、高级筛选、批量导入、修改或匿名公开 API。
10. React 管理界面
10.1 设计原则与视觉系统
管理端采用轻量、内容优先的专业工具风格,不套用营销落地页布局,不使用重型侧边栏、玻璃拟态、大面积渐变或装饰性动效。界面只提供当前单管理员与提示词管理所需的导航和操作。
视觉令牌:
- 主色:
#2563EB。 - 页面背景:
#F8FAFC。 - 内容表面:
#FFFFFF。 - 主文字:
#0F172A。 - 次要文字:
#475569。 - 边框:
#E2E8F0。 - 危险操作:
#DC2626。 - 当前只实现浅色主题;所有业务组件使用语义化主题令牌,不在组件内散落原始颜色值。
- 字体优先使用本机
Noto Sans SC、PingFang SC、Microsoft YaHei与系统无衬线字体,不依赖 Google Fonts 网络加载。 - 间距使用 4/8 像素节奏,正文移动端不小于 16 像素。
- 图标统一使用 Phosphor 线性图标,不使用 emoji 充当结构或操作图标。
10.2 导航与路由
管理端采用顶部导航,不为当前少量功能引入侧边栏。顶部显示产品名“提示词管理”、当前“提示词”入口和账号菜单;当前入口必须有明确的文字与视觉选中状态。退出放在账号菜单中,并与普通导航操作分开。
/login:管理员登录。/prompts:提示词分页列表和关键词搜索。/prompts/new:填写提示词、选择图片、本地预览并上传。/prompts/:id:查看完整提示词、图片和技术信息。/account/password:修改本人密码。
登录成功后直接进入 /prompts,不保留空 Dashboard。
路由切换后将键盘与读屏焦点移到主内容标题。由详情页返回列表时恢复原搜索条件、页码和滚动位置。会话过期后跳转登录页,并在重新登录后返回原目标页面。
10.3 登录与账号
- 登录页使用居中的单列卡片,桌面端最大宽度约 420 像素,移动端保留页面边距。
- 用户名和密码始终显示可关联的文字标签,不使用占位符代替标签。
- 密码输入支持系统密码管理器、自动填充、粘贴与显示/隐藏切换。
- 字段错误就近展示,并通过
aria-describedby关联;提交错误使用role="alert"通知读屏软件。 - 提交期间按钮禁用并显示加载状态,防止重复提交。
- 修改密码页沿用相同表单规则;成功后按认证策略重新登录。
10.4 提示词列表
- 顶部工具区提供关键词搜索与唯一主操作“上传提示词”。搜索提交、清空与加载状态必须可见。
- 内容使用图片卡片网格:桌面 3 列、平板 2 列、手机 1 列。
- 卡片展示图片缩略图、提示词摘要、宽高、文件大小和创建时间;卡片主体进入详情页。
- 删除入口始终可见或可由明确的更多操作按钮访问,不依赖鼠标悬停才出现。
- 图片容器预留稳定比例空间以避免布局跳动;首屏外图片延迟加载。
- 分页位于列表底部,默认 20 条,可切换 50 条;页码变化后焦点与滚动行为可预测。
- 空列表、无搜索结果、加载失败分别提供明确说明与下一步操作。
10.5 新建提示词
- 桌面端使用左右分栏:左侧表单,右侧图片预览;移动端改为上下排列,提示词优先、图片预览随后。
- 表单只包含提示词正文和单张图片,不包含标题、来源、模型、尺寸或质量输入。
- 提示词输入展示固定标签、50,000 字符计数与规范化说明。
- 图片区域同时提供拖放和普通文件选择按钮;拖放不是唯一上传方式。
- 选择文件后立即显示本地预览以及真实可获得的文件名、大小和图片尺寸,但最终格式与尺寸以后端校验结果为准。
- 页面只有一个主提交按钮。提交期间锁定重复操作并显示进度反馈。
- 上传失败后保留提示词正文、本地图片预览和浏览器仍可保留的文件选择状态,错误信息说明原因和修复方式。
- 多字段失败时,在页面顶部显示可聚焦的错误摘要,并保留字段旁的内联错误;摘要项可跳转到对应字段。
10.6 提示词详情与删除
- 桌面端以大图和完整提示词双栏展示,移动端上下排列。
- 展示图片、完整提示词、宽高、文件大小、MIME 类型、图片哈希和创建时间。
- 提供“复制提示词”操作并给出非抢焦点的成功反馈。
- 永久删除放在与普通操作分离的危险区域,使用危险色和文字共同表达风险。
- 删除前弹出二次确认,明确说明提示词与 MinIO 图片都会永久删除且不可恢复。
- 确认弹窗打开后焦点进入弹窗并被约束在其中;取消是默认安全操作,关闭后焦点回到触发按钮。
10.7 响应式、动效与可访问性
- 验证宽度至少覆盖 375、768、1024 和 1440 像素,不允许移动端横向滚动。
- 移动端输入控件高度和主要点击目标不小于 44 像素,交互目标之间保留至少 8 像素间距。
- 所有功能必须可用键盘完成,焦点顺序与视觉顺序一致;交互控件显示至少 2 像素清晰焦点环。
- 正文和背景的正常文本对比度不低于 4.5:1;状态不得只依靠颜色表达。
- 有意义的图片提供描述性替代文本;装饰性图标从辅助技术中隐藏,独立图标按钮提供可访问名称。
- 过渡仅用于反馈状态变化,时长约 120–200 毫秒,只动画
transform与opacity;不使用 GSAP、滚动揭示或装饰性入场编排。 - 尊重
prefers-reduced-motion,减少或关闭非必要过渡。 - Toast 使用
aria-live="polite"且不抢焦点;错误必须同时包含原因和恢复办法。
11. 一致性与错误处理
11.1 创建
text
认证和 CSRF
→ 校验提示词与唯一性
→ 校验图片内容、格式、大小和分辨率
→ 生成 UUID 与对象键
→ 上传 MinIO
→ 写入 MySQL若 MinIO 上传成功但数据库写入失败,后端立即补偿删除已上传对象。
11.2 永久删除
text
数据库标记待删除
→ 删除 MinIO 对象
→ 删除数据库记录删除必须幂等且可重试。MinIO 暂时失败时不得让数据库记录直接消失;已经进入删除流程的记录不出现在普通列表中。
11.3 HTTP 错误
400:提示词或图片校验失败。401:未登录或会话失效。403:CSRF 或权限校验失败。404:记录不存在。409:提示词重复或账号状态冲突。503:MinIO 暂时不可用。500:未预期服务端异常,响应不得泄露堆栈或密钥。
12. 数据库迁移与隔离环境
后台尚未正式发布,因此不追加永久保留旧 CMS 历史的删除迁移。重写迁移为最小认证和提示词结构,并重建明确的隔离测试数据库 coding_blog_qa。
允许清除 coding_blog_qa 中现有测试数据。不得操作其他 MySQL 容器或数据库。管理员通过引导流程重新创建。
13. 测试与验收
13.1 后端
- 登录、退出、修改密码、会话失效和 CSRF。
- 提示词为空、超长和重复冲突。
- PNG、JPEG、WebP 正常上传。
- 伪造格式、超 10 MB、超宽高或超总像素图片被拒绝。
- 相同图片可配不同提示词上传。
- 分页、创建时间倒序和关键词搜索。
- 15 分钟签名预览。
- 永久删除、幂等重试和 MinIO 失败路径。
- 数据库写入失败后的 MinIO 补偿清理。
13.2 React 前端
- 未登录路由保护。
- 登录、退出和修改密码。
- 创建表单校验和本地图片预览。
- 上传失败后保留用户输入。
- 分页、搜索、详情和永久删除确认。
- 返回列表时恢复搜索、页码和滚动位置。
- 登录和上传表单的标签、错误关联、错误摘要与焦点管理。
- 删除确认弹窗的键盘操作、焦点约束和焦点恢复。
- 375、768、1024 和 1440 像素宽度下的关键布局。
prefers-reduced-motion下不执行非必要过渡。
13.3 整体
- 重建
coding_blog_qa。 - 初始化私有桶
prompt-results。 - 后端全量测试通过。
- React 测试与生产构建通过。
- 静态博客原有测试与构建不受影响。
- 浏览器真实验证登录、上传、查看、搜索、删除和修改密码。
仓库中与本次无关的既有测试失败必须单独列明,不得误报为本次回归。
14. 明确不在本轮范围
- 公开提示词 API 或公开页面接入。
- 将新数据写入现有
gpt-image-prompts.json。 - 导入现有静态提示词档案。
- 一条提示词对应多张图片。
- 编辑提示词或替换图片。
- 批量上传、CSV 或 ZIP 导入。
- 提示词标题、来源、模型、分类或标签。
- 图片内容去重。
- 后台博客文章、分类、标签和配置管理。
- 自动部署、发布快照、导出和回滚。
15. 成功标准
重构完成后,公开博客仍由 Markdown/JSON 静态构建;废弃 CMS 功能及其数据表不再存在;管理员可通过 React 后台安全登录,将一条不重复的提示词和一张合规图片保存到 MySQL 与私有 MinIO,并能分页搜索、查看和永久删除记录。