# React + Go 内容平台技术选型 > 状态:提案 > > 更新时间:2026-07-19 > > 适用范围:SuBlog 从 Markdown 静态博客演进为可运营的内容系统。 ## 1. 目标与边界 ### 目标 - 提供公开的文章阅读、搜索、归档、标签、系列、SEO 和评论体验。 - 提供受权限控制的运营后台,支持文章草稿、发布、定时发布、修订、媒体上传和用户管理。 - 保留当前博客的视觉识别:技术图标环绕头像、主题切换动画、轻量内容阅读体验。 - 将业务规则、鉴权和数据一致性收敛到 Go 服务,前端不持有业务写入逻辑。 ### 不在第一阶段解决 - 多租户、计费、复杂工作流和实时协同编辑。 - 微服务、消息队列和 gRPC。 - 直接把 Nuxt/Vue 组件转换为 React 组件。 首版采用模块化单体:一个 Next.js 应用、一个 Go API、一个 PostgreSQL 实例和一个 S3 兼容对象存储。先保证内容链路可靠,再按真实运营需求拆分。 ## 2. 结论 采用以下组合: | 层级 | 选型 | 决策 | | --- | --- | --- | | Web 前端 | Next.js App Router + React + TypeScript | 采用 | | 样式与基础组件 | Tailwind CSS + shadcn/ui | 采用 | | 视觉动效 | Magic UI | 采用,仅用于体验增强 | | 后台服务 | Go + Gin | 采用 | | 数据库 | PostgreSQL | 采用 | | 媒体存储 | S3 协议对象存储,开发环境使用 MinIO | 采用 | | 内容编辑器 | 首版 Markdown;富文本需求明确后引入 Tiptap | 延后 | | API 契约 | OpenAPI 3.1 + TypeScript 客户端生成 | 采用 | | 服务端状态 | TanStack Query,仅用于后台的客户端交互 | 采用 | Next.js 的 App Router 默认使用服务端组件,适合将公开文章页在服务端从 Go API 获取数据后输出 HTML,同时把编辑器、筛选和管理表单限制在客户端组件中。[Next.js Server and Client Components](https://nextjs.org/docs/app/getting-started/server-and-client-components) shadcn/ui 的组件代码进入项目而非被黑盒依赖包封装,适合作为长期维护的后台设计系统;Magic UI 则只用于图标云、主题切换等差异化效果,不作为后台基础组件。[shadcn/ui Introduction](https://ui.shadcn.com/docs) [Magic UI Icon Cloud](https://magicui.design/docs/components/icon-cloud) ## 3. 总体架构 ```mermaid flowchart LR Visitor["读者"] --> Web["Next.js Web\n公开站点与运营后台"] Operator["运营人员"] --> Web Web -->|"SSR / HTTPS API"| API["Go API\n鉴权与业务规则"] API --> DB[("PostgreSQL")] API --> Storage[("S3 / MinIO\n媒体资源")] API --> Events["内容发布事件"] Events --> Revalidate["Next.js 缓存失效端点"] Revalidate --> Web ``` 生产环境使用同一主域名,反向代理按路径分流: ```text https://example.com/ -> Next.js https://example.com/admin/ -> Next.js https://example.com/api/v1/ -> Go API ``` 这样浏览器访问 API 不需要 CORS,Go 可使用 `HttpOnly`、`Secure`、`SameSite=Lax` 的会话 Cookie。Next.js 仅负责渲染、路由和 API 调用适配;文章发布、权限判断、文件签名和数据写入只能由 Go 服务完成。 ## 4. React 前端设计 ### 4.1 框架职责 | 区域 | 渲染方式 | 数据方式 | 说明 | | --- | --- | --- | --- | | 首页、文章页、归档、标签、系列 | Server Components 优先 | Next 服务端请求 Go API | SEO、首屏和分享信息优先 | | 搜索、评论、主题切换、头像图标云 | Client Components | 按需调用 API | 仅加载必需的浏览器逻辑 | | `/admin` | Client Components 为主 | TanStack Query 调用 Go API | 表格、筛选、编辑和乐观更新 | | 登录页 | Server + Client Components | Go 会话 API | 不在浏览器保存访问令牌 | TanStack Query 管理后台的远程数据缓存、重新获取和写入后的失效;公开页面不为此引入客户端状态层,直接使用 Next 的服务端数据获取和缓存策略。[TanStack Query Queries](https://tanstack.com/query/latest/docs/framework/react/guides/queries) ### 4.2 UI 与视觉系统 以 Tailwind CSS 的语义变量作为唯一主题来源,先定义 `background`、`foreground`、`card`、`muted`、`border`、`primary` 等 token,再由 shadcn/ui 和业务组件共同消费。不要将页面色值散落在组件中。 Magic UI 的定位是“效果层”,使用范围限定为首页品牌区、空状态和少量内容提示;文章正文、后台表格、表单和弹窗保持克制、信息密度优先。 #### 现有视觉资产迁移 | 现有能力 | 当前实现 | React 迁移方案 | 可复用范围 | | --- | --- | --- | --- | | 技术图标环绕头像 | `vue-icon-cloud` + CSS | Magic UI `IconCloud` | 图标 slug、图片 URL、尺寸与视觉参数可复用;Vue 组件代码不可复用 | | 主题切换 | Vue `useColorMode` + View Transitions API | `next-themes` 管理主题状态,Magic UI `AnimatedThemeToggler` 负责动画 | 动画原点、时长、`prefers-reduced-motion` 降级和 CSS token 可复用 | | 深浅色样式 | CSS 变量 | `globals.css` 的 Tailwind/shadcn token | 色彩语义和视觉值可复用,选择器需重写 | 现有项目并没有直接使用 Magic UI:头像云是 Vue 专用组件,主题切换是自行封装的 View Transitions API。React 端可直接采用 Magic UI 对应组件的实现路径,官方提供了 `IconCloud` 和基于 View Transitions API 的主题切换组件。[Magic UI Theme Toggler](https://magicui.design/docs/components/animated-theme-toggler) ### 4.3 内容编辑策略 首版以 Markdown 为正文规范,延续现有文章资产并降低导入风险: - 后台编辑器保存 `body_markdown`,预览由与公开页面一致的渲染器生成。 - 文章的标题、摘要、标签、发布时间、封面和状态使用结构化字段保存。 - 每次保存创建修订快照,发布操作产生不可变的发布记录。 当存在非技术作者、复杂嵌入内容或协同编辑的明确需求时,再评估 Tiptap。Tiptap 提供 React 集成和可组合扩展,但其 Markdown 能力仍处于 beta 文档范围,因此不将它作为首版 Markdown 数据规范的前提。[Tiptap Editor](https://tiptap.dev/docs/editor/getting-started/overview) ## 5. Go 后端设计 ### 5.1 模块边界 ```text apps/api/ ├── cmd/api/ # 程序入口、依赖装配、优雅退出 ├── internal/ │ ├── identity/ # 用户、角色、会话、登录限制 │ ├── content/ # 文章、标签、系列、草稿、修订、发布 │ ├── media/ # 上传策略、文件元数据、对象存储 │ ├── site/ # 站点设置、导航、主题等运营配置 │ ├── audit/ # 管理操作审计日志 │ ├── platform/ # 数据库、缓存、对象存储、时钟、ID │ └── transport/http/ # Gin 路由、鉴权中间件、请求/响应 DTO ├── migrations/ # 仅追加的数据库迁移 └── openapi/ # OpenAPI 源文件与生成配置 ``` 业务模块拥有自己的服务、仓储接口和测试;HTTP handler 只做参数绑定、鉴权调用和响应映射。禁止 handler 直接拼接 SQL,禁止前端绕过 Go 直接访问数据库或对象存储。 ### 5.2 首版数据模型 | 实体 | 关键字段 | 说明 | | --- | --- | --- | | `users` | `id`、`email`、`status` | 运营用户身份 | | `roles` / `user_roles` | `role`、`permission` | RBAC,首版至少管理员、编辑、只读 | | `sessions` | `token_hash`、`expires_at`、`user_id` | 服务端会话,不将访问令牌写入 localStorage | | `posts` | `slug`、`title`、`summary`、`body_markdown`、`status`、`published_at` | 文章当前版本 | | `post_revisions` | `post_id`、`content`、`created_by` | 草稿与发布前可回滚快照 | | `tags` / `post_tags` | `slug`、`name` | 标签关系 | | `media` | `object_key`、`mime_type`、`size`、`created_by` | 文件元数据,文件本体在对象存储 | | `audit_logs` | `actor_id`、`action`、`target`、`metadata` | 发布、删除、授权等关键操作记录 | 文章状态固定为 `draft`、`scheduled`、`published`、`archived`。状态流转在 `content` 模块校验,数据库事务内同时更新文章、修订和审计日志。 ### 5.3 API 与契约 - 使用 `/api/v1/public/*` 提供公开只读接口,例如文章详情、归档、标签、站点配置。 - 使用 `/api/v1/admin/*` 提供后台接口,并按角色授权。 - 以 OpenAPI 3.1 为唯一接口契约,从契约生成 React TypeScript 客户端;Go handler 的集成测试验证响应符合契约。 - 发布、下线、删除、媒体上传等写入接口要求会话、CSRF 防护、审计日志和幂等键。 - 发布成功后,Go 使用签名事件调用 Next.js 缓存失效端点;不得依赖固定时间等待缓存过期。 ## 6. 仓库结构 迁移完成后采用 pnpm workspace 与 Go 模块并存的单仓库: ```text sublog/ ├── apps/ │ ├── web/ # Next.js │ │ ├── app/ │ │ │ ├── (public)/ │ │ │ └── admin/ │ │ ├── components/ │ │ │ ├── ui/ # shadcn/ui 受控源码 │ │ │ ├── effects/ # Magic UI 及品牌动效 │ │ │ └── content/ │ │ ├── lib/api/ # 生成的 API client 与查询封装 │ │ └── styles/ │ └── api/ # Go 服务 ├── contracts/openapi/ # API 契约 ├── deploy/ # Compose、反向代理、生产部署说明 ├── scripts/migrate-content/ # 现有 Markdown 导入工具 └── docs/ ``` 现有 `content/posts//index.md` 仅作为迁移输入和归档备份;迁移完成后,运行时内容的唯一来源是 Go API + PostgreSQL。 ## 7. 分阶段迁移 ### 阶段 0:技术验证 完成一条最小闭环:Go 提供一篇文章的公开读取接口,Next.js 服务端渲染文章详情,Magic UI 图标云和主题切换在 React 中正确运行。 验收:SEO 元信息可见、首次加载无主题闪烁、禁用动效偏好下主题可正常切换。 ### 阶段 1:公开内容迁移 1. 建立 PostgreSQL 迁移、`posts`、`tags`、`post_revisions` 和公开 API。 2. 编写一次性导入脚本,读取现有 frontmatter 和 Markdown 正文。 3. 重建首页、文章详情、列表、归档、标签和系列页面。 4. 保留原 URL,缺失页面使用 301 重定向,逐页比对标题、描述、封面和正文。 验收:全部已发布文章可访问;迁移前后的 URL、SEO 字段和图片链接无回归。 ### 阶段 2:运营后台 1. 建立登录、会话、RBAC 与审计日志。 2. 实现文章列表、草稿编辑、预览、发布、定时发布和修订回滚。 3. 接入对象存储的预签名上传与媒体选择器。 4. 接入内容发布事件与 Next.js 缓存失效。 验收:编辑只能操作授权资源;发布后公开页与 sitemap 在可预期时间内更新;审计记录可追踪。 ### 阶段 3:运营能力完善 - 后台搜索、内容质量检查、死链检测与站点设置。 - 评论审核、内容推荐和访问统计。 - 基于实际作者需求决定是否引入 Tiptap、协同编辑或内容审批流。 ## 8. 关键风险与验证 | 风险 | 影响 | MVP 验证 | | --- | --- | --- | | Markdown 导入丢失格式 | 历史内容不可逆受损 | 保留原文件,导入后逐篇 hash 与人工抽检 | | Next 缓存未失效 | 发布后读者仍看到旧内容 | 发布接口后调用签名失效端点,编写端到端测试 | | 前后端职责混杂 | 规则分散且难以审计 | 代码审查禁止 Next Route Handler 承载业务写入 | | 富文本过早引入 | 数据格式和编辑器维护成本暴涨 | 首版只验证 Markdown 编辑与预览 | | 动效影响后台可用性 | 性能与无障碍下降 | Magic UI 仅在品牌区域使用,尊重 `prefers-reduced-motion` | ## 9. 测试与上线标准 - Go:领域服务单元测试、HTTP + PostgreSQL 集成测试、迁移升级测试、权限矩阵测试。 - Web:组件测试覆盖主题与编辑表单;Playwright 覆盖登录、草稿、发布、撤回、文章访问和上传。 - 契约:CI 生成 TypeScript API client,并检测 OpenAPI 变更。 - 发布:健康检查、数据库备份、对象存储生命周期规则、错误监控和审计日志保留策略齐备后才接入真实运营数据。 ## 10. 最终决策 React + Go 适合本项目向内容平台演进,但必须以“Next.js 负责体验与渲染、Go 负责全部业务与数据”为边界。优先迁移公开阅读链路,再实现后台闭环;不要在第一阶段同时重写全部页面、接入富文本和实现复杂工作流。