项目仓库与前后端架构

返回主题索引 · 平台架构与数据库设计 · 返回 cmmuu 统一平台

1. 架构结论

cmmuu 主站、统一账号中心、统一管理后台、reqforge 和后续工具统一放入 一个 GitHub 私有 Monorepo。仓库内包含多个可独立部署的 TypeScript 前端和一个 Go 模块化单体后端,共享 UI、鉴权客户端、API 类型、国际化和工程配置。

这不是把所有代码耦合成一个应用,而是:

  • 一个仓库统一版本、规范、依赖和 CI/CD。
  • 多个前端应用独立构建、独立域名、独立部署。
  • 一个 Go 后端按平台模块与产品模块隔离。
  • 一个 PostgreSQL 集群起步,以事务和 service_id 保证数据一致性与产品隔离。
  • GitHub Actions 根据变更路径只构建受影响的应用。

2. 当前事实与目标状态

已在现有文档确认

  • reqforge 当前设计记录为 Next.js 全栈应用。
  • 未来产品方向是 TypeScript 前端配合 Go 后端。
  • 主站和子域名产品需要统一账号、订阅、后台与运维能力。

本文确定的目标状态

  • 新的统一平台仓库暂命名为 cmmuu-platform,正式创建时可由用户确认最终仓库名。
  • reqforge 作为第一个产品模块逐步接入,不进行一次性大爆炸重写。
  • 前端框架尽量统一;若现有 reqforge 使用 Next.js,则优先保持 Next.js,除非某个产品有明确的纯 SPA 或其他框架需求。
  • Go 后端早期保持单进程模块化单体,避免个人开发阶段提前承担微服务成本。

本文是目标架构设计,不代表对应代码仓库已经创建或迁移完成。

3. 逻辑架构

flowchart TD
    Repo["GitHub 私有 Monorepo"] --> Frontend["TypeScript 前端工作区"]
    Repo --> Backend["Go 模块化单体"]
    Repo --> Contract["OpenAPI 契约与生成客户端"]
    Repo --> Database["数据库迁移"]
    Repo --> Delivery["路径触发 CI/CD"]
    Frontend --> Main["cmmuu 主站"]
    Frontend --> Account["统一账号中心"]
    Frontend --> Admin["统一管理后台"]
    Frontend --> Reqforge["reqforge 产品"]
    Backend --> Platform["平台模块<br/>账号、订阅、支付、权益"]
    Backend --> Product["产品模块<br/>reqforge 与后续工具"]
    Contract --> Frontend
    Backend --> Postgres["PostgreSQL"]
    Backend --> Redis["Redis"]

4. 推荐目录结构

cmmuu-platform/
├── apps/
│   ├── web-main/                    # cmmuu.com 主站
│   ├── web-account/                 # account.cmmuu.com 账号中心
│   ├── web-admin/                   # admin.cmmuu.com 统一后台
│   ├── web-reqforge/                # reqforge.cmmuu.com
│   └── api/
│       ├── cmd/
│       │   ├── server/              # HTTP API 组合入口
│       │   └── worker/              # 异步任务入口,确有需要时启用
│       ├── internal/
│       │   ├── platform/
│       │   │   ├── identity/        # 用户、外部身份、会话
│       │   │   ├── catalog/         # 服务、套餐、价格
│       │   │   ├── subscription/    # 订阅生命周期
│       │   │   ├── billing/         # 订单、支付事件、退款
│       │   │   ├── entitlement/     # 权益与配额判定
│       │   │   └── admin/           # 后台与审计
│       │   ├── products/
│       │   │   └── reqforge/        # reqforge 专属业务
│       │   └── shared/               # 日志、配置、数据库等基础适配
│       ├── migrations/              # Go 后端关联迁移入口或嵌入文件
│       ├── go.mod
│       └── go.sum
├── packages/
│   ├── ui/                           # 跨前端设计系统与组件
│   ├── auth-client/                  # OIDC 登录与会话客户端
│   ├── api-client/                   # 由 OpenAPI 生成的 TypeScript 客户端
│   ├── i18n/                         # English 与中文公共文案能力
│   ├── config-eslint/                # ESLint 共享配置
│   └── config-typescript/            # TypeScript 共享配置
├── contracts/
│   └── openapi/                      # API 单一契约来源
├── db/
│   ├── migrations/
│   │   ├── platform/                 # 平台公共表迁移
│   │   └── products/
│   │       └── reqforge/             # 产品专属表迁移
│   └── seeds/                         # 仅放可公开的基础种子数据
├── deploy/
│   ├── compose/                       # 本地、测试、生产 Compose 文件
│   ├── cloudflare/                    # 域名与边缘配置模板
│   └── environments/                  # 非敏感环境清单,不存密钥
├── docs/
│   └── adr/                           # 架构决策记录
├── scripts/                           # 可复现的开发、构建与运维脚本
├── .github/
│   └── workflows/
│       ├── ci-web.yml
│       ├── ci-api.yml
│       ├── ci-contract.yml
│       ├── migrate-database.yml
│       └── deploy.yml
├── package.json
├── pnpm-workspace.yaml
├── turbo.json
├── Makefile
└── README.md

4.1 工具约定

  • TypeScript 工作区:新仓库默认使用 pnpm workspace
  • 增量任务:默认使用 Turborepo 或等价的依赖图工具;正式初始化前先确认现有 lockfile,避免无理由切换包管理器。
  • Go:只有一个后端模块时使用单个 go.mod;出现第二个确实独立的 Go 模块后再增加根级 go.work
  • API:OpenAPI 文件作为前后端契约来源,生成 packages/api-client,避免前端手写重复类型。
  • 常用动作通过 Makefile 或跨平台脚本统一,但命令名称应在仓库初始化后以真实脚本为准,不在设计文档中假定已经存在。

5. 前端边界

5.1 独立应用

应用域名主要职责部署边界
web-maincmmuu.com品牌、产品入口、登录入口、用户总览独立构建部署
web-accountaccount.cmmuu.com登录、注册、身份绑定、账号安全、授权确认独立构建部署,安全策略更严格
web-adminadmin.cmmuu.com用户、产品、套餐、订阅、订单和审计管理独立构建部署,强制管理员权限
web-reqforgereqforge.cmmuu.comAI 前置产品交互独立构建部署

5.2 共享范围

适合放入 packages/

  • 无产品业务含义的 UI 组件和设计令牌。
  • OIDC 登录、令牌刷新和退出逻辑。
  • OpenAPI 生成的请求客户端和类型。
  • 国际化基础设施、日期、货币与通用校验。
  • ESLint、TypeScript、测试和构建配置。

不放入 packages/

  • reqforge 的页面流程和业务规则。
  • 管理后台的特权业务操作。
  • 需要访问数据库或服务端密钥的代码。
  • 为了“复用”而过早抽象、只有一个调用方的业务组件。

5.3 强制边界

  • 浏览器前端不得直连 PostgreSQL 或 Redis。
  • 前端不得持有 Apple、Google、GitHub、支付渠道或数据库的服务端密钥。
  • 所有业务权限由 Go API 最终判定,前端隐藏按钮不等于授权。
  • 后台和普通用户前端使用不同 OIDC Client 与会话策略。
  • 默认 English 并支持中文,所有 Web UI 使用 mobile-first 响应式设计。

6. Go 后端边界

6.1 模块化单体

后端以一个部署单元起步,但代码按业务域组织:

  • platform:所有产品都需要的账号、服务目录、订阅、支付、权益、审计。
  • products/reqforge:只属于 reqforge 的生成任务、文档、配额消耗等业务。
  • shared:数据库、Redis、日志、追踪、配置、邮件和对象存储适配器。

依赖方向:

cmd -> platform/products -> domain interfaces -> infrastructure adapters

产品模块可以调用平台公开接口,不直接读写平台模块的内部表;平台模块也不依赖 reqforge。

6.2 拆分服务的触发条件

仅在出现以下明确证据时拆分微服务:

  • 某模块需要独立扩缩容,资源曲线与主 API 明显不同。
  • 发布频率和故障域已经相互影响。
  • 独立团队需要拥有完整交付边界。
  • 合规或客户隔离要求独立数据与运行环境。
  • 单体在完成索引、缓存和查询优化后仍无法满足目标。

“未来可能做大”不构成拆分理由。

7. API 契约

  • contracts/openapi/ 是浏览器客户端与 Go API 的契约来源。
  • Pull Request 必须检查 OpenAPI 语法、兼容性和生成客户端是否更新。
  • 删除字段或改变语义属于破坏性变更,必须先发布兼容版本并完成迁移。
  • 错误响应统一包含稳定错误码、用户可展示消息和请求追踪标识。
  • 认证令牌携带稳定的用户和客户端身份;service_id 仍需由服务端可信配置校验。

8. 数据库与迁移

8.1 单库起步

  • PostgreSQL 是账户、订单、订阅、权益和产品业务数据的事实来源。
  • 平台公共表与产品专属表共用一个数据库集群,迁移文件按目录和所有者区分。
  • 公共订阅表使用 service_id 隔离产品;产品专属表必须保留明确的产品归属和外键。
  • Redis 只保存可重建缓存、短会话、验证码和限流状态。

8.2 迁移规则

  • 迁移文件只追加,不修改已经在生产执行过的迁移。
  • 结构变更使用 expand-contract:先增加兼容结构,再迁移数据,最后删除旧结构。
  • 发布流程先运行兼容迁移,再发布应用;破坏性收缩放到后续独立版本。
  • 迁移前创建可恢复备份,自动化流程必须支持失败停止,禁止失败后继续发布。
  • 本地、CI、测试和生产使用同一套迁移文件,不手工改生产表结构。

9. GitHub Actions 路径触发

变更路径必须执行
apps/web-main/**主站 lint、test、build、部署
apps/web-account/**账号中心安全检查、test、build、部署
apps/web-admin/**后台 test、build、权限冒烟、部署
apps/web-reqforge/**reqforge test、build、部署
packages/ui/**packages/i18n/**构建所有依赖该包的前端
packages/auth-client/**构建并测试所有登录相关前端
contracts/openapi/**契约检查、Go API 测试、客户端重新生成、前端类型检查
apps/api/**Go format、vet、test、build、镜像扫描、后端部署
db/migrations/**迁移静态检查、临时数据库升级测试、人工批准后的生产迁移
deploy/**Compose 或基础设施检查,不默认触发全部应用重建

实施要点:

  • 使用 paths 或受影响项目计算减少 GitHub 托管分钟。
  • 前端、后端和迁移使用独立工作流,避免任何小改动都执行全仓部署。
  • 公共包变化必须构建它的全部消费者,不能只构建公共包本身。
  • 生产部署使用 GitHub Environment 审批、最小权限 Token 和可追踪版本号。
  • 镜像按 Git commit SHA 标记,不使用不可追踪的单一 latest 作为回滚依据。

10. 分支与发布

个人开发阶段保持简单:

  • main 始终保持可部署。
  • 功能在短生命周期分支完成,通过 Pull Request 合并。
  • CI 通过后才合并;数据库迁移、认证和支付改动需要额外审查。
  • 每个可部署应用拥有独立版本与部署记录,不要求所有应用同时发布。
  • 回滚优先回滚应用镜像;数据库采用向前修复,避免直接回滚已写入业务数据的迁移。

11. 本地开发与测试

  • 本地 Compose 只启动 PostgreSQL、Redis、邮件捕获器等依赖,不强迫所有前端同时运行。
  • 每个前端可独立启动,通过本地 API 网关或统一环境变量访问 Go API。
  • 单元测试:各 TypeScript 包与 Go 模块分别执行。
  • 契约测试:验证 OpenAPI 与 Go Handler、生成客户端一致。
  • 集成测试:使用临时 PostgreSQL 和 Redis,测试事务、幂等和订阅隔离。
  • E2E:至少覆盖登录、选择产品、购买或切换套餐、权益生效和后台审计。
  • 前端必测 375、390、768 和 1280 以上视口。

12. 密钥与配置

  • 仓库只提交 .env.example 和非敏感配置,不提交真实 Token、Cookie、私钥或数据库密码。
  • 本地个人密钥通过本机安全存储或约定的私密环境目录读取。
  • CI 使用 GitHub Environments 与 Secrets,按应用和环境隔离。
  • 生产容器使用只读文件系统、非 root 用户和最小网络权限。
  • 前端只暴露明确允许公开的环境变量;任何 PUBLIC 前缀变量都按公开信息处理。

13. 新增产品的标准动作

新增一个产品时,依次完成:

  1. apps/ 创建独立前端应用。
  2. apps/api/internal/products/ 创建后端业务模块。
  3. 在平台 services 目录登记唯一 service_id 与域名。
  4. planspricesentitlements 定义该产品的套餐和权益。
  5. 添加产品专属数据库迁移,不复制用户和订阅表。
  6. 更新 OpenAPI 契约并重新生成 TypeScript 客户端。
  7. 添加路径触发 CI、部署环境、域名和可观测性配置。
  8. 增加登录、授权、订阅隔离和关键业务 E2E。
  9. 更新统一管理后台的产品入口。
  10. 完成备份、恢复和回滚验证后上线。

14. reqforge 迁移策略

现有文档记录 reqforge 为 Next.js 全栈。迁移目标是保留可用功能并逐步抽出 Go 后端:

  1. 先建立统一账号、服务目录、订阅和权益模块。
  2. reqforge 前端先通过稳定 API 契约接入平台能力。
  3. 按业务域逐个迁移 Next.js 服务端逻辑到 products/reqforge
  4. 每迁移一个域,执行新旧接口的结果与权限回归测试。
  5. 全部关键流程达到功能等价后,再移除对应的 Next.js 服务端实现。

这样可以避免一次性重构导致功能异常,也保留后续安全测试所需的稳定行为基线。

15. 验收清单

  • 一个 GitHub 私有仓库包含全部目标应用,但每个应用可独立构建部署。
  • TypeScript 前端没有数据库直连和服务端密钥。
  • Go 后端的平台模块和产品模块依赖方向清晰。
  • OpenAPI 变更能自动生成并校验 TypeScript 客户端。
  • 公共包变化会触发所有受影响应用测试。
  • 数据库迁移经过临时数据库升级测试和生产前备份。
  • 每个产品的套餐、订阅和权益都按 service_id 隔离。
  • 新增产品不需要复制账号、支付和管理后台基础设施。
  • 所有应用有独立部署记录、回滚版本和日志入口。
  • reqforge 迁移前后关键功能与权限测试等价。