总体架构
# 总体架构
版本 v1.4,2026-10-22。返回总览。本文包含目标架构;M0 已实施范围和验证边界以 实施与验收 为准。
# 1. 系统形态
一个代码仓库,后端采用 Go workspace + 多个 go.mod,前端独立 pnpm workspace。物理模块对应能力边界,不等于每个模块都必须独立部署。默认部署 Go API 与 worker;通用工作流引擎先作为同进程 Go 模块运行,共享选定业务数据库。流程负载需要独立扩容时,可按相同接口拆成 Go 服务。
业务、认证、权限、流程、审批和资源适配均使用 Go。工作流与业务同库时通过 UnitOfWork 提交原子变更;需要跨库/远程协作时使用幂等命令、outbox/inbox 和对账,不使用分布式事务伪装成本地事务。
# 2. 技术选型
| 部位 | 选择 | 使用约束 |
|---|---|---|
| 工程 | go.work + 能力模块独立 go.mod | 明确无环依赖和模块公开契约,按锁定版本统一发布 |
| HTTP | Gin | Gin Context 不穿透业务层 |
| 持久化 | GORM + database/sql + 方言适配 | MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、DM、TiDB 逐项认证 |
| 事务 | framework 中的 UnitOfWork | 同库本地事务;方言负责锁、序列、分页和错误归一 |
| 认证 | 多 realm、多 client 的 identity;OIDC 接入成熟身份提供方 | 管理员、会员、平台运营、服务身份隔离,支持 SSO |
| 缓存 | Redis 版本化权限/菜单/会话定位缓存 | 权威版本在业务主库,精确失效和故障降级 |
| 消息 | Event、Redis Streams、RabbitMQ、Kafka、RocketMQ 可选适配器 | 基础合同和后端特性分开,可靠事件使用 outbox/inbox |
| 工作流 | 纯 Go 通用 workflow 组件,现有库评估 + 自研缺口 | 文件/文档和业务流程共用;引擎持久化走统一方言层 |
| 前端 | Vben 5 / 默认 web-antd | 动态菜单、按钮权限、表单和 BPMN 设计器适配 |
| 合同 | OpenAPI 3.0.3 + 版本化事件 schema | 生成前端类型,业务 DTO 不暴露 ORM 实体 |
| 迁移 | 统一迁移命令 + 每方言脚本和锁实现 | 具体 runner 在 M0 验证 DM/Oracle 后确定,不能假定一个工具覆盖全部 |
每次部署选择一种业务数据库,可按模块配置消息路由;不是同时把一笔事务写入七种库或向五个消息后端广播。多数据库和消息后端的认证方案见 兼容层设计。
# 3. 多模块结构
demo/
fago/ 统一Git仓库
fago-server/ 后端workspace
go.work
configs/config.{development,test,production}.yaml
apps/fago-server/ go.mod,组装与命令入口
cmd/{api,worker}/
apps/fago-cli/cmd/fago-cli/ 同仓CLI运维入口
modules/
fago-contracts/ go.mod,Actor/事件/窄端口,不放业务实现
fago-framework/ go.mod,HTTP/配置/日志/事务/基础设施端口
fago-security/ go.mod,JWE 内容加密、敏感字段/日志脱敏
fago-identity/ go.mod,多用户多终端、会话、OIDC
fago-authorization/ go.mod,RBAC、数据范围、权限缓存
fago-tenancy/ go.mod,租户、套餐、透明隔离
fago-system/ go.mod,用户、角色、部门、岗位、菜单
fago-infra/ go.mod,字典、参数、文件、通知、任务、生成器
fago-workflow-core/ go.mod,定义/编译/执行/持久化/定时器
fago-workflow-approval/ go.mod,任务/会签/或签/参与人策略
fago-workflow-resource/ go.mod,资源端口和版本/授权规则
fago-documents/ go.mod,文件/文档版本、ACL、审批状态
fago-bpm/ go.mod,表单/流程设计与业务入口
business/ 后续每个业务拥有 go.mod
adapters/
database/{fago-mysql,fago-postgres,fago-oracle,fago-sqlserver,fago-mariadb,fago-dm,fago-tidb}/
messaging/{event,redis,rabbitmq,kafka,rocketmq}/
fago-migrations/{mysql,postgres,oracle,sqlserver,mariadb,dm,tidb}/
tests/{contract,integration}/
fago-vben5/ Vben 所需 workspace 结构
apps/web-antd/src/
packages/ internal/
pnpm-workspace.yaml
pnpm-lock.yaml
api/{openapi.yaml,events/}
deploy/{compose,proxy}/
docs/
这是完整目标结构;M0 落地 13 个模块,M1 增加 fago-security 后当前为 14 个独立模块,配置与安全说明见 配置与数据安全。M0 及后续待建模块见 实施与验收。数据库/消息 adapter 每个子目录按依赖与构建要求使用独立 go.mod,避免默认构建强制引入 Oracle/DM 客户端;app 用显式装配清单选择已认证驱动。module path 使用实际仓库地址确定,不在规划时虚构可发布域名。
依赖 DAG:contracts → 无业务依赖;security → 无业务依赖;framework → contracts/security;能力模块 → contracts/framework;adapters → 基础端口;apps/server → 所需模块和 adapters。业务模块通过消费者定义的窄接口协作,由 app 注入,不循环引用对方实现。workflow-core 不依赖 system/documents,候选策略和资源适配由上层实现并注入。
每个模块的 implementation 放各自 internal 中,公开包暴露构造器和服务契约;别的模块不能跨 internal 目录调用 repository。go.work 用于本地协作,CI 既按工作区测试,也在 GOWORK=off 条件下通过已发布版本或临时本地模块代理验证独立依赖;不用仅在工作区生效的隐式替换掩盖缺失 require。统一 release train、模块版本清单与依赖升级流程在 M0 固定。
Vben 不能只复制单应用目录:需保留共享包、配置和别名依赖闭包。M0 从锁定快照裁剪其他演示应用、mock 和文档站,保留许可证与来源。
2026-10-28 前端按用户确认恢复官方 vue-vben-admin BasicLayout/AuthPageLayout 与配套原生导航、标签和主题系统,继续使用固定快照与既有目录 fago-vben5。应用层把当前 Fago 授权快照桥接到仅内存的官方 store,不复制 token、不启用示例消息;权限校验和原业务模块保持原边界。Vue/Router/Pinia 统一运行时实例,避免 workspace peer 快照导致上下文不一致。实际验证见 M5 实施记录。
M5 当前 fago-infra 已独立接入字典/参数,其 internal/runtime 承载实现,公开 facade 暴露服务与 DTO。消费者定义 TenantGate,由 app 注入 system 的公开同库权限/锁/审计桥接;infra 不导入 system,system 也不导入 infra。读取在 repeatable-read 只读快照复核当前会话/权限,写入沿用租户→账号→会话锁序;回调不得提交事务或产生外部网络副作用。文件通过同一桥接实现短事务预约/完成与事务外 S3 IO,持久 tombstone/租约由独立 worker 恢复清理;消息原语及 Event/Redis 适配器已验证;站内通知通过独立后台范围和同库回执/审计装配到正式 Event worker。v19 定时任务按同库计划/运行/执行历史和独立后台范围装配到 worker,内置处理器只受理站内通知;正式 worker 现可显式选择 Event/Redis Streams,SQL 待办与通知受理积压由 API 只读采样并发布到本机指标口;broker 全量监控、保留期清理与 R2.3 恢复整体验收仍待完成。
# 4. 包内分层
每个业务包按实际规模设置 handler、service、repository、model、dto 文件。包大到难以阅读时才拆子包,只对真实的可替换边界定义接口。
调用关系:HTTP → service → repository。service 处理不变量、事务和跨模块用例;repository 处理 SQL。handler 负责参数校验、身份上下文提取和错误映射,既不直接查询数据库,也不返回数据库 model。
依赖约束:framework 不依赖业务实现;identity 不依赖 system 的 HTTP 实现;authorization 通过窄接口读取角色和部门信息;system/业务包通过 authorizer 获取访问范围。apps/server 负责注入,禁止用全局 DB 或服务注册表绕过边界。
跨模块的事务由发起用例的 application service 编排。共享同一事务句柄的 repository 由事务工厂构造,事务内禁止退回全局连接。避免“用户已创建但角色关联失败”的半成功结果。GORM 支持事务闭包,但正确传播事务仍由项目负责。官方事务文档 (opens new window)
# 5. 数据流与一致性
R1 每个受保护请求从业务主库验证会话撤销、用户状态、租户状态和授权版本,避免 Redis 失效延迟造成越权。缓存可存版本对应的计算结果,但必须与本次权威版本匹配;缺失或不确定时重新计算,不能默认放行。
权限变更事务更新授权关系并递增租户 authz_version。会话撤销、密码修改和用户禁用直接更新业务主库状态。承诺是:变更提交后开始的新请求使用新状态;已经通过授权的在途请求不承诺被强制中止。敏感写入在事务内复查相关状态并采用必要的行锁。
R2 的业务变更、审计和 outbox 事件在同一业务数据库事务提交;worker 至少一次投递,消费者依据 eventId 去重。邮件、短信或对象存储调用不放进长数据库事务,不宣称跨外部服务 exactly-once。
# 6. 扩展能力
| 能力 | 接口边界 | 首次引入时必须解决 |
|---|---|---|
| 文件 | Storage.Put/Get/Delete、文件元数据 service | 对象归属、大小和类型、授权下载、清理补偿 |
| 通知 | 模板 + 渠道适配器 + 发送任务 | 租户隔离、重试、脱敏、幂等和渠道回执 |
| 定时任务 | 调度记录 + 租约 + 执行器 | 多副本抢占、超时、重试、人工重跑与幂等 |
| 代码生成 | 元数据 → 模板 → 预览/下载 | 合同、迁移、权限种子、前端页面、覆盖冲突 |
| 工作流 | ProcessService/TaskService 适配器 | BPMN 语义、流程版本、事务、任务授权、审计 |
| 支付 | 订单状态机 + 渠道适配器 | 签名、回调幂等、金额、对账、退款、敏感操作 |
调度记录由数据库持久化,租约和抢占通过方言层实现;消息 transport 可选 Redis、RabbitMQ、Kafka、RocketMQ。流程定时器由 workflow-core 持久化,worker 通过租约和 fencing token 执行,不重复创建第二套调度记录。各 transport 的延迟、顺序和重试语义通过能力声明暴露。
# 7. 部署与运维
生产建议 HTTPS 同域:/ 静态前端,/api/ 转发 API;开发 Vite 代理 /api 到 Go,以便 cookie、Origin 与刷新机制和生产一致。平台和租户后台采用不同路由及会话 cookie。
本地默认 Compose 包含 MySQL、Redis;完整能力 profile 增加对象存储和经验证不依赖 Java 的 OIDC 提供方。其他数据库/消息后端使用独立测试 profile。生产使用环境变量/Secret 管理密码和密钥,API 和 worker 使用最小权限账号;迁移账号与运行账号分离。
API 支持请求超时、body 大小限制、可信代理范围、优雅退出、连接池上限与取消传播。/health/live 不访问外部依赖;/health/ready 验证业务主库、迁移版本和启用功能的必要依赖,不暴露凭证。Redis 限流不可用时登录和刷新返回 503,普通读请求可降级不使用缓存,不能跳过 SQL 鉴权。
R1 提供请求日志、错误率、延迟分位数、数据库连接池、登录失败与授权拒绝指标;R2 再加 outbox 积压、任务重试和存储失败。指标标签禁止使用 userId/tenantId 等高基数字段,详细归属留在受控日志。
R1 发布前演练数据库备份恢复、迁移失败处理、应用回滚和密钥轮换。采用 expand/contract 迁移,先兼容再切换,最后删除旧列;涉及数据删除时通过备份和修复迁移恢复,不能依赖自动 down migration。
# 8. 建议的容量验证目标
待真实业务校正的首轮基准:单台 4 vCPU/8 GB API、独立 MySQL、100 个租户、10 万用户和 50 个并发活跃后台用户。固定分页查询/详情/简单写入混合脚本,在无外部渠道调用时验证 p95 ≤ 300 ms、5xx < 0.1%。这不是承诺吞吐,必须记录数据分布、SQL、缓存冷热、测试时长和资源曲线;达不到先定位索引、SQL和连接池,再决定拆服务。
# 9. 研发流程
API 先更新 OpenAPI 与样例,再生成前端类型;Go DTO 可由合同生成或逐项校验,选一种并在 M0 固定。业务需求提交同时检查服务端权限、租户归属、分页上限、审计和必要索引。
CI 验证 Go 格式/vet/测试、前端 lint/typecheck/build、OpenAPI lint、关键 MySQL 集成测试及迁移空库升级。发布候选执行 E2E 与隔离回归。演示 mock 不进入生产构建,也不作为业务功能完成依据。
# 10. 通用工作流边界
workflow-core 负责模型编译、持久化 token/节点状态、并行 join、命令幂等、定时器与恢复;workflow-approval 负责候选、会签/或签和任务动作;workflow-resource 只定义受信资源接口。documents/业务模块实现文件、文档和业务单据适配器;bpm/forms 内置 form-instance 资源适配器,让在线独立表单无需业务模块即可发起,并提供表单、设计器和管理 API。
同库时资源状态、审批动作、流程状态和审计使用同一事务提交;外部文件字节保留在对象存储,异步处理走可靠任务。独立数据库/服务模式通过 outbox/inbox/补偿协调,不能跨库假定原子。完整设计见 工作流方案。
实例、命令、job/timer 固定 engineVersion,运行时语义与二进制版本、compilerVersion 分开。新实例按所选定义的 requiredEngineVersion 执行,默认切换不重绑旧定义。发布/回滚必须覆盖活动实例和仍可发起定义的运行时需求。
退役采用持久化的 enabled/draining/retired 准入状态:先关闭版本新发起,再停用或用新版本定义替代旧入口,最后排空活动实例、受理命令、job/timer 和执行租约。准入检查、首次受理与引用写入同事务,和退役/定义启用锁定同一版本记录,避免零计数后插入新实例;只有准入全关闭且引用为零才卸载处理器。运行中实例默认不迁移,R3.4 才增加显式迁移;这些准入/退役保护从 R3.1 就必须存在。
# M0 工程约束落地
前后端统一由fago仓库维护;后端目录为 fago/fago-server/,前端目录为 fago/fago-vben5/;模块目录/module path 使用 fago- 前缀,Go 包名使用 fago 前缀,main 包遵守 Go 入口规范。Go 固定 1.27.3。后端已配置 Gitee 子仓库远程,模块仍使用明确的本地命名空间 fago.local/fago;正式发布前迁移至实际仓库地址。M0 选择手写 Go DTO + 实际响应合同校验,前端类型由 OpenAPI 生成。开发中文注释要求见仓库根目录 AGENTS.md。
# M3 平台能力与扩展边界
fago-tenancy 管理套餐、能力、租户生命周期及平台审计;PlatformGuard 与 Initializer 是该模块消费的窄端口,由 app 分别注入身份复核与系统种子适配器。fago-system 自己定义 TenantPolicy,用同一事务检查可用状态与账号配额。模块不互相调用 handler 或导入别的模块 internal,也不为平台主体提供租户业务查询入口。
平台写事务固定平台账号→当前平台会话→目标套餐→租户 ID 升序;平台账号不参与租户账号锁。写入用 READ COMMITTED,等待套餐或租户锁后不沿用守卫查询形成的旧快照。租户系统写入继续先锁租户,再锁目标账号与会话。套餐更新先锁所有引用租户,再收窄能力/配额并推进租户授权版本;分配和创建先锁目标套餐,不能逃过受影响租户的检查。账号创建和权威 count 在同一个租户锁内,回滚不消耗名额。
当前同库事务适用于 R1 的首轮 100 租户容量目标,完整容量证据仍在 M4。套餐批量收窄会锁定所有引用租户;规模增大时应把不可变套餐版本、权威 packageVersion 校验及用量账本作为独立演进设计,并重新证明立即撤权和并发配额,不能直接改为异步失效而降低当前保证。未来文件、任务等资源分别定义自己的配额单位与事务端口,不把用户计数泛化成未经验证的万能配额引擎。
新增能力通过迁移发布稳定 capability code,权限显式绑定能力,菜单仍由同一有效权限集合投影。未配置或未启用的能力不放行。租户会话代次处理停用/恢复/续期 fencing,授权版本处理套餐/角色/上限变化,两个版本职责独立。实际结果见 M3 实施记录。
# 平台基础设施分层与Cron执行(v29增量)
平台目录、平台私有参数与租户配置使用独立服务/表/身份。平台公共标准及默认模板提供显式版本发布,租户复制后独立维护;没有缺省回退或自动同步副本,代码状态机不由在线字典驱动。部署与安全配置仍走环境加载或专用策略入口。
平台与租户共用一份Cron日期计算和持久执行状态机,平台父表没有tenant_id,后台不创建零租户。平台需要处理租户业务时,只在已锁定父运行事务受理最多100个独立子运行,不取全部租户行锁;每个子业务事务按真实租户→计划→运行检查当前状态/套餐、租约/版本/准入代次,再提交统计与执行历史。单租户拒绝、限额或暂时失败不回滚其他租户结果。
Cron只计算UTC触发点,时区、DST和错过策略明确;只有cron调度,人工执行是独立幂等命令。旧非cron计划升级后停用待配置且保留历史,不自动改变执行语义。具体操作见字典与参数、定时任务与恢复,实际检查及未认证边界见M5增量记录。