项目仓库与前后端架构
返回主题索引 · 平台架构与数据库设计 · 返回 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.md4.1 工具约定
- TypeScript 工作区:新仓库默认使用
pnpm workspace。 - 增量任务:默认使用 Turborepo 或等价的依赖图工具;正式初始化前先确认现有 lockfile,避免无理由切换包管理器。
- Go:只有一个后端模块时使用单个
go.mod;出现第二个确实独立的 Go 模块后再增加根级go.work。 - API:OpenAPI 文件作为前后端契约来源,生成
packages/api-client,避免前端手写重复类型。 - 常用动作通过 Makefile 或跨平台脚本统一,但命令名称应在仓库初始化后以真实脚本为准,不在设计文档中假定已经存在。
5. 前端边界
5.1 独立应用
| 应用 | 域名 | 主要职责 | 部署边界 |
|---|---|---|---|
web-main | cmmuu.com | 品牌、产品入口、登录入口、用户总览 | 独立构建部署 |
web-account | account.cmmuu.com | 登录、注册、身份绑定、账号安全、授权确认 | 独立构建部署,安全策略更严格 |
web-admin | admin.cmmuu.com | 用户、产品、套餐、订阅、订单和审计管理 | 独立构建部署,强制管理员权限 |
web-reqforge | reqforge.cmmuu.com | AI 前置产品交互 | 独立构建部署 |
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. 新增产品的标准动作
新增一个产品时,依次完成:
- 在
apps/创建独立前端应用。 - 在
apps/api/internal/products/创建后端业务模块。 - 在平台
services目录登记唯一service_id与域名。 - 在
plans、prices、entitlements定义该产品的套餐和权益。 - 添加产品专属数据库迁移,不复制用户和订阅表。
- 更新 OpenAPI 契约并重新生成 TypeScript 客户端。
- 添加路径触发 CI、部署环境、域名和可观测性配置。
- 增加登录、授权、订阅隔离和关键业务 E2E。
- 更新统一管理后台的产品入口。
- 完成备份、恢复和回滚验证后上线。
14. reqforge 迁移策略
现有文档记录 reqforge 为 Next.js 全栈。迁移目标是保留可用功能并逐步抽出 Go 后端:
- 先建立统一账号、服务目录、订阅和权益模块。
- reqforge 前端先通过稳定 API 契约接入平台能力。
- 按业务域逐个迁移 Next.js 服务端逻辑到
products/reqforge。 - 每迁移一个域,执行新旧接口的结果与权限回归测试。
- 全部关键流程达到功能等价后,再移除对应的 Next.js 服务端实现。
这样可以避免一次性重构导致功能异常,也保留后续安全测试所需的稳定行为基线。
15. 验收清单
- 一个 GitHub 私有仓库包含全部目标应用,但每个应用可独立构建部署。
- TypeScript 前端没有数据库直连和服务端密钥。
- Go 后端的平台模块和产品模块依赖方向清晰。
- OpenAPI 变更能自动生成并校验 TypeScript 客户端。
- 公共包变化会触发所有受影响应用测试。
- 数据库迁移经过临时数据库升级测试和生产前备份。
- 每个产品的套餐、订阅和权益都按
service_id隔离。 - 新增产品不需要复制账号、支付和管理后台基础设施。
- 所有应用有独立部署记录、回滚版本和日志入口。
- reqforge 迁移前后关键功能与权限测试等价。