首页/作品/城市体检数据管理平台
中大型业务系统 · 双端 · 生产运维

城市体检数据管理平台

一套省级双端生产系统:移动端负责调研数据采集与板块填报,网页端负责指标配置、多层级权限、 数据汇聚与批量出表。多级组织树五级联动,是真实有人在用的系统。

已上线,公开成果 Spring Cloud · Python · Vue 3 · 小程序 参与研发

一、这是什么

一个面向多层级组织的指标数据管理系统。业务上要解决的是:几十项指标、五级组织、多个填报方, 怎么让数据从采集到汇总到出表这条链路可管、可查、可复算。

难点不在单个功能,在于三个互相牵制的约束同时成立:

  • 指标会变指标的定义、口径、填报要求每年调整。如果指标写死在代码里,每次调整都要发版——这在业务上是不可接受的。
  • 权限分层五级组织,每一级只能看自己管辖范围内的数据。这不是简单的功能权限,是数据行级可见性。
  • 填报会错几十个单位填报,数据质量参差。必须有审核环节,而且退回意见要能回传到填报人。

我在其中的角色是「参与研发」。参与了双端的全流程梳理与开发、数据结构与字段设计、 指标计算分析的数据梳理与流程梳理,以及数据库管理运维与线上缺陷修复。 下面写的是这套系统的技术形态与我实际经手的那部分。

二、规模

2
端(小程序 + 网页)
5
级组织联动
双栈
后端服务
生产
状态(非演示)

后端是双栈的:重型业务服务跑在 Spring Cloud 系框架上,AI 相关的部分用 Python。 前端同样是两端——移动端与网页端,各自有不同的交互约束(移动端要弱网可用,网页端要处理大数据量表格)。

三、三个最值得讲的设计

1 · 指标配置驱动,而不是写死在代码里

指标的定义(名称、单位、填报字段、校验规则、所属板块)全部存在数据里, 界面由这份配置动态渲染。新增或调整一个指标,改的是配置数据,不是代码。

这带来一个连锁好处:指标的口径变化也变成了数据变更,可以带版本、可以追溯 「去年这一项是怎么定义的」。如果写死在代码里,口径的历史只能靠翻代码仓库。

代价是渲染逻辑变复杂、类型安全变弱,且配置写错时报错位置离根因较远。见第五节。

2 · 权限分成两层:功能权限与数据可见性

只做功能权限(能不能进某个菜单)是不够的——各级单位用的是同一套功能, 区别只在于能看到哪部分数据。所以权限模型实际是两层: 角色决定能做什么,组织层级决定能看哪些行。

组织层级(决定可见数据范围) 省级 市级 区县级 街道 社区 第一层 · 功能权限 角色 → 能进入哪些模块 审核者 / 填报者 / 管理者 回答「能不能做」 第二层 · 数据可见性 所在层级 → 能读到哪些数据行 含下级汇总,不含同级与上级明细 回答「能看多少」 两层同时成立才算通过 —— 只做功能权限的系统,各级看到的数据是一样的
权限分两层。数据可见性按组织层级计算,是这套系统里最容易做错、也最影响正确性的部分。

3 · 审核状态机与意见回传

填报数据走状态机:草稿 → 待审 → 通过,或退回。关键在于退回不是打回重填,而是带着意见回到填报人—— 否则填报人只知道「没过」,不知道哪里有问题,来回沟通的成本会吃掉整条流程的收益。

状态流转的每一步都留痕:谁在什么时候改的、意见是什么。这既是为了追责,也是为了复算—— 发现某个数字不对时,能顺着流转记录找到它是在哪一步被改动的。

四、我实际经手的技术工作

工作通用化的说法涉及的问题
双端全流程梳理与开发 前后端接口联调与业务闭环实现 两端的数据契约一致、状态同步、弱网容错
数据结构与字段设计 元数据驱动建模 指标可配置化之后,表结构怎么设计才不至于频繁变更
指标计算分析的数据梳理与流程梳理 指标口径到字段的映射与计算编排 口径写在文档里与写在代码里不一致的问题
数据库管理运维与缺陷修复 生产库巡检、数据修复、缺陷定位与回归 生产环境的缺陷定位远比开发阶段难——没有干净的重现环境
异构填报数据的汇聚 多来源结构化数据的汇聚管道与结构校验 不同填报方提交的数据形态不一致,直接入库会污染下游统计

五、决策记录

为什么指标要做成配置驱动,而不是写死在代码里
为什么这么选
指标口径每年调整是这类系统的常态。写死在代码里意味着每次调整都要改代码、测、发版, 而调整往往有时间压力(评审节点临近)。把最常变的东西做成数据,是把变更成本从「一次发版」降到「一次配置」。
放弃了什么
类型安全与编译期检查。配置写错时,问题会在运行时才暴露,且报错位置往往离根因很远—— 表格渲染不出来,可能真正的错在某个字段的类型定义上。这要求在配置层加校验。
什么条件下会失效
如果指标是稳定的、三五年不动的,配置驱动就是过度设计——多出的抽象层只增加理解成本而没有任何收益。 判断标准是变更频率,不是「配置化听起来更高级」。
为什么权限要拆成功能权限与数据可见性两层
为什么这么选
多层级组织下,各级用的是同一套功能,区别只在能看到哪些数据。 如果只用功能权限去表达,就会出现「给市级建一套菜单、给区县建一套菜单」这种不可维护的做法。
放弃了什么
简单性。每次数据查询都要带上层级过滤条件,漏掉一处的后果是该看的值看不到、或者不该看的看到了。 所以这类过滤必须收敛到统一入口,不能靠每个接口自己记得加。
什么条件下会失效
如果组织层级是平的(没有上下级)、或者所有使用者看到的数据范围一致,两层模型就是多余的。 单层功能权限足够。
为什么提交接口必须做幂等
为什么这么选
移动端填报的网络环境不可控。用户点提交后没收到响应,很自然的反应是再点一次—— 如果接口不幂等,这一次重试就产生两条重复记录,而重复数据会直接污染后续的汇总统计, 且很难被发现(统计结果只是偏大,看不出异常)。
放弃了什么
一点点灵活性。幂等键一旦生成就不能重复使用,某些「先提交后修改」的操作需要走单独的更新路径,不能靠重复提交实现。
什么条件下会失效
如果填报场景是有线网络下的后台操作、不存在重试,幂等的复杂度就没必要承担。 它是被弱网环境逼出来的设计,不是通用最佳实践。

六、失败与边界

这一节是这类系统里最少被讲、但最能说明问题的部分——因为生产环境的问题,永远比设计时预想的多。

印象最深的一类缺陷:数据质量引发的连锁问题

填报数据入库时,部分字段的实际形态与预期不符——这不是代码 bug,是真实数据的多样性。 问题在于这类异常不会在写入时报错,而是在统计与出表环节才暴露出结果异常, 此时已经很难回溯到是哪一条原始数据造成的。

处理方式分两层:写入侧加结构校验,把不合规的数据拦在入口并给出明确提示(而不是静默接受); 统计侧加异常检测,让结果异常时能快速定位到可疑的原始记录。教训是 校验必须前置,事后发现的成本高一个量级。

线上排查与开发阶段的差别

  • 没有干净环境开发时改一行重跑就复现了;生产上不能随便改数据、不能随便重启,定位靠的是日志、数据比对与排除法。
  • 修复要先备份数据修复脚本必须先备份再执行,且要能在出错时回退。直接在生产库上跑 UPDATE 是不可接受的。
  • 缺陷会重复同一个字段的问题修过一次,换个入口又出现。根因往往不在具体的接口,而在缺少统一的校验层——修一处不解决问题,得修架构。

已知不足。指标配置化牺牲了类型安全,配置错误只能在运行时发现; 数据可见性的过滤分散在多个查询入口,靠规范约束而非强制机制保证一致性—— 这是当前结构下最容易出问题的地方,如果能重做会把这层过滤下沉到统一的数据访问层。

七、链接与状态

状态已上线运行,省级公开成果
源码不公开——内部生产系统,源码与业务数据受约束
可提供的以上技术形态与设计说明;移动端可由公开渠道扫码体验

内部生产系统,源码与业务数据不公开。以上为公开展示范围内的方法说明—— 不含具体指标口径、业务数据、原始台账与内部后台画面。