企业业务系统不是把页面和数据库简单连起来。真正可长期使用的系统,需要把用户界面、业务规则、数据存储、权限控制和部署运维拆开,让每一层承担清晰责任。这样后续加功能、改流程、查问题时,系统不会越改越乱。
典型架构链路
- 浏览器 / 小程序 / APP
- 前端路由与表单校验
- API 网关 / 后端接口
- 业务服务层:订单、库存、客户、审批
- 数据库与文件存储
- 权限、日志、监控、备份
前端层:负责交互,不承载核心业务规则
前端应该处理页面展示、表单校验、状态提示和用户体验,但不要把关键业务判断写死在页面里。比如库存能否出库、订单能否作废、审批能否撤回,最终都应该由后端接口统一判断。
API 层:让不同终端使用同一套业务能力
官网表单、小程序、管理后台、APP 都可以调用同一组 API。API 层需要处理参数校验、身份认证、限流、错误码和返回格式,让前端不用直接接触数据库。
业务服务层:系统价值真正发生的地方
订单状态流转、库存扣减、客户分配、审批流、消息通知等规则应该沉淀在业务服务层。这样未来即使更换前端,核心业务逻辑仍然稳定。
数据库层:先保证数据结构可追踪
企业系统常见问题不是没有页面,而是数据无法追溯。设计数据库时要考虑主表、明细表、状态字段、创建人、更新时间、操作记录和软删除策略。
权限与审计:决定系统能不能进入真实业务
真实业务里不同角色看到的数据不同,能操作的按钮也不同。权限不只是菜单控制,还包括数据范围、操作权限、字段可见性和审计日志。
部署层:上线后要能备份、回滚和排查
小团队也应该有基础的 Docker 部署、Nginx 反向代理、数据库备份、日志查看和健康检查。上线只是开始,后续可维护才是关键。
脱敏项目复盘:制造订单、库存与生产协同的分层设计
制造类业务最容易出现“一个页面改动牵动整套系统”。订单、物料、库存、生产任务和出入库相互关联,如果把规则写在页面事件或数据库脚本里,短期开发很快,后续每次变更都难以判断影响范围。
业务模型
我们先识别订单、物料需求、库存流水、生产任务和交付单五类核心对象,明确哪些是业务事实,哪些只是计算结果。订单确认触发需求,领料和完工形成库存流水,交付只能引用可用成品。每个状态都写明进入条件、允许操作和撤销方式,让口头流程成为可以测试的规则。
产品形态
销售工作台关注交期与缺料风险,计划员关注待排产和物料齐套,仓库关注可执行的收发任务,管理者看到异常而不是全部明细。详情页以业务时间线串联订单、任务和库存凭证,用户不需要在多个模块之间记编号、手工核对上下游。
技术解决方案
首期采用模块化单体:接口层处理鉴权和输入,应用层编排用例,领域层保存状态规则,基础设施层负责数据库、消息和外部系统。模块间通过明确服务接口交互,跨事务通知使用 Outbox,数据库保留库存流水等不可变事实。这样既避免过早拆微服务,也能在业务量和团队规模增长后按边界拆分。
难点设计
跨模块一致性不能依赖一条超长事务。订单撤销、领料失败或消息重复时,系统要有补偿动作和人工处置队列;库存结余只是流水汇总的缓存,出现差异可以重算。状态迁移记录操作者、来源和关联单据,使线上异常能够还原,而不是只看到最终值。
用户体验
分层架构最终要落到业务反馈:缺料时明确缺哪种物料、差多少、影响哪些订单;操作失败时说明当前状态和下一步,而不是返回技术错误码。跨模块信息通过订单时间线组织,让用户不需要理解服务边界也能完成工作。
产品效果与验收
验收同时观察订单按期率、缺料发现提前量、库存差异、人工跨表核对次数,以及新增状态或规则的改动范围。还要模拟撤单、重复消息和库存重算,确认系统能恢复。架构的价值是让系统可持续改变,而不只是代码目录更整齐。
复杂项目中的分层取舍:不是层数越多越专业
分层的目标是隔离变化,而不是照搬一张架构图。第一版只有一条订单链路时,模块化单体通常比微服务更稳:部署简单、事务边界清楚、定位问题更快。我们会按客户、订单、库存、结算等业务能力划分模块,通过接口调用而不是跨模块直接改表。等到团队规模、发布频率或容量确实形成独立边界,再拆服务。
事务边界要跟业务一致
创建出库单、扣减可用库存、记录库存流水属于一个不可分割的本地事务;给客户发通知则可以异步完成。如果把所有动作都放进同一事务,外部接口超时会拖垮核心业务;如果完全拆开,又可能出现主记录成功、流水缺失。常见做法是本地事务保存业务数据和待发送事件,再由后台任务投递,消费端使用事件 ID 保证幂等。
接口契约比“前后端分离”更重要
接口需要明确字段含义、空值规则、错误码、分页方式和版本策略。对于金额、时间、状态枚举和文件地址,不能让各端自行解释。我们会把鉴权、参数校验和错误响应放在统一入口,把业务规则留在服务层;接口变更通过兼容字段或新版本逐步迁移,避免后台、小程序和第三方调用同时被破坏。
可观测性要带上业务上下文
只记录一条“500 error”几乎无法排查。日志至少应包含请求 ID、用户、业务单号、模块、动作和错误阶段;后台任务还要记录重试次数与外部响应摘要。指标关注请求延迟、错误率、队列堆积、数据库连接和关键业务失败数。这样团队才能回答“是系统慢了,还是某个供应商接口慢了”“一批订单为什么没有通知”等具体问题。
一个业务请求穿过各层时,怎样保持数据一致
应用层组织用例,领域层守住不变量
以“提交订单”为例,API 层负责身份解析、输入格式和 request_id;应用层加载客户、价格与库存,组织一次完整用例;领域对象判断订单是否允许提交、金额是否一致;仓储层在事务内持久化。控制器不直接拼 SQL,领域对象也不负责发送短信。职责分开后,同一套提交规则才能被后台、开放 API 和批量任务复用。
事务外动作通过 Outbox 可靠衔接
订单写库和消息发送无法共享数据库事务时,可以在同一事务内同时写订单与 outbox_event。独立消费者再发送通知、同步 ERP,并用 event_id 做幂等。失败事件保留重试次数和错误原因。这样即使服务在提交后瞬间重启,也不会出现订单已经成功但后续系统永远不知道的断链。
查询模型可以优化,但不能复制业务真相
复杂看板不必每次联查十几张业务表,可以通过汇总表或事件消费生成读模型。但订单状态、库存余额等核心事实仍只有一个写入来源,读模型允许延迟且必须可重建。我们会标明统计口径、更新时间和数据版本,避免为了页面速度在多处维护同一字段,最后各模块数字对不上。
用同一个标识串起日志、审计和指标
网关生成或透传 request_id,应用日志、SQL 慢查询、异步事件和第三方调用都记录该标识;涉及业务数据修改时再关联 operator_id 与 business_id。监控同时关注接口延迟、错误率、队列积压和关键状态停留时间。排查问题时可以从一个订单反查整条链路,而不是在不同容器里猜测时间点。
落地前建议确认
- 是否有多端访问需求
- 核心业务规则是否都在后端
- 数据库是否记录状态和操作人
- 是否有权限、日志、备份和回滚方案
