# 后端几何读模型源核查 本报告仅依据 `E:\pipe-ner-server` 当前可读源码、既有 SQL 和第一方设计说明进行静态核查。指定目标文件经两次路径发现确认原先不存在,因此本次新建;未覆盖旧研究。使用 research 技能与默认运行模型;技能要求的嵌套后台代理被工具深度上限拒绝,研究由本委派代理直接完成。未修改后端;未运行构建、测试、服务、HTTP 或浏览器。由于用户约束及工作区规则,已跳过 build/debug 验证。 “源码事实”不等于已部署数据库事实:本次未连接数据库,不能确认迁移是否落库、现网字典值、对象数量或坐标质量。下文建议均不是现有接口已承诺的新契约。 ## 1. 可直接采用的结论 - 三类几何源分别是统一管网线段、燃气管点、窨井台账;它们具有真实 ID 和坐标字段,但**没有坐标可信校核状态/来源/人员/时间字段**。不能因为经纬度不为空、范围合法、WGS84 注释或已有 GIS 返回 Feature,就把 `coordinateVerified` 置为 true。[管网实体:23–96]()、[燃气管点实体:22–89]()、[窨井实体:22–76]()。 - **三套数字/类型域不能复用**:`MonitorPoint.pointType` 为 1供水/2排水/3燃气;`PipeNetworkBase.networkType` 的通用 GIS 口径为字符串 0燃气/1排水/2供水;`GasPipePoint.pointType` 是 String 设施类别,源码只列“阀门/调压/计量/阴极保护/弯头/三通/其它”,未找到其真实存储编码字典。[监测点枚举:11–28]()、[通用 GIS:40–63]()、[燃气管点类型:35–48]()。 - 当前业务驾驶舱 map adapter **没有接入这三种设施几何**,只组合监测点、设备与设备类型;监测点/设备均显式传 `coordinateVerified=false`。现有快照也只有 `types / monitoringPoints / smartDevices`,不能声称已有 pipeLines/gasPipePoints/manholes 读模型。[业务 map adapter:198–274]()、[快照顶层:9–21]()。 ## 2. 三种几何实体、ID 与 networkId 语义 | 几何源 | 权威身份与关联 | 几何字段 | 删除/其它边界 | | --- | --- | --- | --- | | PipeNetworkBase | `app_user.pipe_network_base`;`networkId` 对应 `network_id`,String,`ASSIGN_UUID`;`networkCode` 是设施编码,不能当关联主键 | `startLongitude/startLatitude/endLongitude/endLatitude` 四个 BigDecimal;字段注释明确 WGS84;只能证明一个两端点线段,没有中间折点或拓扑 | `delFlag` String,`@TableLogic(0→2)`;业务 `status` 为独立 String 字段 | | GasPipePoint | `app_user.gas_pipe_point`;`pointId` Long 自增;`networkId` String 注释“所属管线ID”;另有冗余 `networkName` | `longitude/latitude` BigDecimal;实体注释没有声明具体 CRS | `@TableLogic(0→2)`;业务 status 注释 0正常/1异常/2停用,与 delFlag=2 含义不同 | | ManholeBase | `app_user.manhole_base`;`manholeId` String UUID;`networkId` String 注释“关联管网设施ID” | `longitude/latitude` BigDecimal;实体注释没有声明具体 CRS | `@TableLogic(0→2)`;没有 pointType/行业字段,业务 status 独立 | 表中每行依据:[管网身份/类型:23–37]()、[管网状态/删除/坐标:61–95]();[管点身份/关联/类型/坐标:22–48]()、[管点状态/删除:66–88]();[窨井身份/关联/坐标:22–45]()、[窨井状态/删除:59–75]()。 `GasPipePoint.networkId → PipeNetworkBase.networkId` 有实际使用证据:设备全量 VO 读取管点的 networkId、对统一管网做 `selectBatchIds`,再按 `point.getNetworkId()` 匹配管网并补设施字段。因此它表示所属设施记录 ID,不是网络集合、设备 ID、监测点 ID,也不是 networkCode。[设备组装关联:1021–1044]()、[补管点/管网字段:1079–1096]()。 `ManholeBase.networkId` 的“关联统一设施”只能由实体注释确认;当前窨井查询/保存服务未 join 管网或检查 networkId 是否存在。燃气管点保存/修改也只检查自身编码及自身 ID,不检查所属管线存在、是否燃气或是否已删除。管网删除服务仅检查管网存在后删除,未检查管点/窨井反向引用。本次没有足够 DDL 证据断言数据库有无外键或级联约束,应把悬空关联作为读模型需要降级的情况。[窨井服务:23–64]()、[管点写入检查:51–78]()、[管网删除:123–156]()。 监测点关系与设施关系须分别建模:`equipment_point_rel.pointId` 是 String 监测点 ID;`gas_pipe_point_device_rel.pointId` 是 Long 管点 ID;窨井关系使用 `manholeId` String。前者实体没有逻辑删除字段,后两者有 `@TableLogic(0→2)`。不能把三个表按相同字段名合并为一种点位关系。[监测点关系:20–38]()、[燃气管点关系:21–46]()、[窨井关系:21–46]()。 ## 3. pointType 真实字典与源码/旧说明冲突 ### 3.1 MonitorPoint.pointType 已有第一方枚举 当前实体将 `pointType` 声明为 Integer,使用 `@TableField(updateStrategy=ALWAYS)`,没有 `exist=false`;枚举是 `WATER_SUPPLY(1) / DRAINAGE(2) / GAS(3)`,`isValid(null)=true`。保存、批量保存、更新均使用枚举校验;列表筛选按整数精确匹配。**null 是源码允许的未分类状态,枚举没有 4窨井或 UNKNOWN 数字值。**[监测点实体:38–40]()、[枚举:11–28]()、[列表/新增:41–80]()、[批量/更新:84–116]()、[校验调用:346–349]()。 当前 map adapter 注释仍说 monitor_point 无行业/类型列;旧后端说明还说 point_type 不存在且兼容字段 `exist=false`。这些陈述与当前实体不一致,不能把旧说明当作当前源码结论。实际 adapter 也未读取 `getPointType()`,仅在关联设备类型集合恰好一个时赋 typeCode;无设备或混合类型仍为 null。**后续若打算用自有 pointType 给空点确定行业,需另行决定读模型契约,并先确认部署 schema;本次静态核查不能证明数据库已加入该列。**[旧说明:195–199]()、[adapter 旧注释:59–61]()、[adapter 实际推导:215–243]()。 ### 3.2 GasPipePoint.pointType 不能编造编码 它是 String;DTO 也是 String;分页 wrapper 直接按原值 `.eq`;保存/更新没有类型枚举白名单检查。实体中文注释只给类别名称,**无法据此证明存储值是 0..6、英文码还是中文文本**。本次对后端 `java/sql/xml` 及相关 `vue/js/ts/json/md` 检索没有发现燃气管点类型种子/枚举;没有读取 live sys_dict_data。后续应保留 `rawPointType`,未知值展示原值/未分类,待真实字典来源确认后再映射,禁止把它套入 MonitorPointTypeEnum 或设备类型字典。[管点实体:41–42]()、[管点 DTO:20–24]()、[查询:23–40]()、[保存/更新:51–78]()。 ## 4. 逻辑删除、选择查询及完整性 三种 mapper 均仅继承 MyBatis-Plus BaseMapper,服务继承 ServiceImpl;结合实体 `@TableLogic(0→2)`,这些标准 list/getById/page/remove 路径的源码意图是只查询正常记录、执行逻辑删除。未运行 SQL,不能声称已验证运行时生成的 SQL。[管网 mapper:7–9]()、[管点 mapper:7–9]()、[窨井 mapper:7–9]()。 - 管网 `/PipeNetworkBase/getList` 返回 `service.list()`;分页按 networkCode/name 模糊匹配、networkType/status 精确匹配;`getOptions()` 只选择 ID/name/code,**不含任何坐标或 networkType**,不能拿下拉列表当几何源。[管网控制器:29–58]()、[分页:42–60]()、[选项:115–120]()。 - 管点 `/api/gas-pipe-point/list-by-network/{networkId}` 只按 networkId 精确查询,按 pointCode 排序,不检查管网存在或有效,也不按业务 status 排除;分页可附 pointType/status;`options()` 同样只有 pointId/name/code,没有 geometry、networkId 或 pointType。[管点控制器:65–76]()、[管点服务:23–48]()。 - 窨井 `/api/manhole/list` 明确返回全量 `service.list()`,可作为保留缺坐标对象的原始台账路径;分页只有 name/code/status 筛选,没有 networkId;`getOptions()` 只有 ID/name/code。[窨井控制器:50–61]()、[窨井服务:23–38]()。 - 直接使用自定义 SQL 必须显式写正常记录条件;供水 GIS 的五类 select 与 overview 均写 `del_flag='0'`。不要假定任意手写 join 都得到 BaseMapper 的逻辑删除保障。[供水 GIS mapper:4–43]()。 ## 5. 业务 GIS 已有实现可以证明什么 ### 5.1 通用 GIS:`/api/gis` 管网接口将 networkType 按标准字符串 0/1/2 与历史别名过滤;未知类型入参按原值精确匹配,不强制降到某个行业。未传类型时查询全部正常管网。仅四坐标非空就输出两端点 LineString,properties 保留 networkId/name/type/code;没有范围、零坐标、可信校核或线长检查。[通用 GIS:35–104]()。 窨井接口只过滤缺经纬度对象,properties 有 manholeId/name/code/status,**丢失 networkId**;设备接口也只判空,虽然接收 equipmentTypeId,却没有将参数应用到查询/循环,实际 `equipmentService.list()`。这两个 GeoJSON 接口都未返回 coordinateValidation。[窨井 GIS:113–138]()、[设备 GIS:141–166]()。 该控制器没有 GasPipePoint 图层;燃气管点当前通过台账/list-by-network 取实体,不能把 `/api/gis/equipments` 当管点图层。[通用 GIS 全控制器:24–168]()。 ### 5.2 供水设施 GIS:`/waterSupply/gis/map` 正式支持 source/plant/pumpStation/pipe/user。管网 features 来自统一 `pipe_network_base`,SQL 要求 `del_flag='0' AND network_type='2'` 且四坐标非空;不会纳入通用 GIS 兼容的 water/WATER_SUPPLY/供水历史值。Service 输出 `pipe:` 身份与 BigDecimal 两端点 LineString,坐标顺序固定 `[longitude,latitude]`。[供水接口:22–43]()、[管线 SQL:16–21]()、[LineString/Feature:118–169]()。 overview 的 `geoCompleteCount` 只代表非空,不代表 VALID/verified;第一方规格明确“完整性只判空,不在后端校验范围或自动纠偏”。详情的 pipe 分支是直接 `getById(id)`,**没有重复 networkType='2' 约束**,因此源码允许供水详情通过真实 ID 读到其它行业管网;应作为来源范围不一致风险记录,不能说已验证越权攻击。[overview SQL:27–43]()、[规格:197–202]()、[详情:55–65]()。 供水设备 GIS 也仅按非空坐标过滤;名为 `bdLon/bdLat` 的字段由 `fillGpsFields` 直接复制原经纬度,并未进行坐标转换。字段名称不能证明 BD-09,不能在接入层再盲目转换。[供水设备点位:173–203]()、[GPS 字段填充:678–688]()。 ### 5.3 排水还存在独立模型 `PipeNetworkInfo` 对应 `app_user.psgw_pipe_network_info`,networkType 是“管线/管点/排口”的形状类别;`points` 是 JSON 字符串,设备关联是逗号串。它不是统一 PipeNetworkBase,实体没有 delFlag/TableLogic,服务删除调用 BaseMapper.deleteById。本次没有建立该 JSON 的 CRS/结构/校核权威,不能把它自动并入本次两端点几何源或按 `0→2` 逻辑删除解读。[排水实体:20–54]()、[排水删除:68–96]()。 ## 6. 可信校验状态与来源 `CockpitCoordinateValidation` 是只读响应结果,只有 state/reason/renderable/crs;不是持久化验证证据。快照的 coordinateVerified 是构造器布尔输入,也没有核验人、时间、来源、坐标版本或证明材料。验证器只能消费“外部已经可信的 boolean”,不能创造可信性。[校验结果:3–19]()、[快照点位:67–97]()、[验证器:11–31]()。 | 输入/检查顺序 | state | reason | renderable | | --- | --- | --- | --- | | coordinateVerified=false,优先于所有数值检查 | UNVERIFIED | UNVERIFIED_COORDINATE | false | | true 且缺经度/纬度 | INVALID | MISSING_LONGITUDE / MISSING_LATITUDE | false | | true 且经度超 [-180,180]、纬度超 [-90,90] | INVALID | LONGITUDE_OUT_OF_RANGE / LATITUDE_OUT_OF_RANGE | false | | true 且 (0,0) | INVALID | ZERO_COORDINATE | false | | true 且通过上述检查 | VALID | null | true | 全部结果固定标 `crs=WGS84`,验证器不转换坐标、不验证 CRS 来源、不检查当地合理范围。表依据:[完整验证器:5–31]()。因此未验证的越界/缺坐标对象仍优先呈 UNVERIFIED;如果另需完整性诊断,应另设诊断事实,不能改 false 为 true 来取得 INVALID。通过范围检查的 `(12,12)` 或错误 CRS 值也不能据此获得业务可信性。 真实业务 map adapter 对监测点和设备都传 false,设备事实 resolver 对绑定设备也用相同验证器传 false;服务逐对象透传真实坐标并生成校验结论,而不是删除不可渲染对象。三类新增设施没有可信来源时应保持相同默认,线段则需要分别验证两端,任何一端未验证/无效均不能渲染整段。[adapter 点位/设备:234–262]()、[设备 resolver:75–81]()、[地图点位校验:283–296]()、[地图独立设备校验:339–351]()。 ## 7. 未知行业如何保留 现有正式行业四个:GAS/WATER_SUPPLY/DRAINAGE/MANHOLE。设备类型树口径是根 1供水/2排水/3燃气/4窨井;沿 parentId 上溯,不将窨井并入排水。未知根、一般缺失中间节点或环返回 null。细节:实现遇到 parentId 恰为 1..4 会直接映射,并不再检查该根记录是否存在;严格“父级缺失全部拒绝”不能仅据注释认定已实现。[行业树:13–62]()。 地图服务解析不出类型、类型 kind 不是 SMART_DEVICE、行业不在正式域时均输出 `industry=null`;默认不排除该对象。未设置 industry/deviceType 筛选时保留,指定正式行业时 null 不匹配;指定 deviceType 时必须字典可解析。请求 industry 的白名单只有四行业,**UNKNOWN 不是已有合法请求值**。[行业入参:176–184]()、[可空行业/过滤:214–245]()。 监测点处理保留有有效 pointCode 的空点、混合类型点与未验证坐标点;行业/类型不确定不是身份无效。适配器只在解析成功的设备类型集合大小=1时填 typeCode;一个未知设备类型不会进入该集合,因此“唯一可解析类型”不等于全部设备类型可信且唯一,后续若强化行业可信度应显式定义混合/缺字典规则。服务仍返回对象及坐标结论,统计的是点位对象与未关联设备对象,不是上图 marker 数。[adapter:211–243]()、[对象过滤/构造:248–296]()、[总量/分页:101–127]()。 建议新设施读模型沿用 `industry=null + 原始 networkType/pointType + 映射原因` 保留未分类对象;以稳定的“对象种类+真实主键”建立身份,networkId 单独表达关联,不把未知值降到排水/燃气。窨井台账作为窨井对象种类可以与其关联管网行业分开表达,避免关联到供排水时将 MANHOLE 身份覆盖。以上为新契约建议;既有 map adapter 还没有设施 SourceType 或这些字段。 ## 8. 漏洞与边界建议(静态发现,未修改实现) 1. **可信状态伪造风险,最高优先级。** 既有 GIS Feature、geoCompleteCount、字段 WGS84 标注、bdLon/bdLat 名称均不提供核验链。设施新读模型默认 UNVERIFIED;接入可信来源时记录来源标识、核验时间/人或流程、CRS、坐标版本,坐标变更后旧校核失效;不要接受前端自报 true。验证器的 boolean 输入与真实 adapter false 的事实见第 6 节。 2. **字典混用与旧资料误导。** 显式维护三套映射;MonitorPoint.pointType 不冒充 equipment_type 叶子 ID,networkType 不套 1/2/3行业枚举;GasPipePoint.pointType 在真实存储字典确认前保留 raw 值。修正“点位无类型列”的旧注释/说明属于后续任务,本次只记录冲突。依据见第 3 节。 3. **关系悬空与错误行业继承。** networkId 应使用统一设施主键查正常管网;查不到时保留设施原始关系与 UNKNOWN/关联缺失,不借 networkName、编码前缀或最近线段补造。三种服务缺反向引用检查的事实见第 2 节;不要把按 networkId 查到管点就当作管网仍有效的证明。 4. **已知查询范围缺口。** 通用 GIS equipments 忽略 equipmentTypeId;供水 pipe detail 未约束 networkType;供水 features 只识别标准 '2',通用 GIS 接受历史别名;窨井 GeoJSON 缺 networkId。后续需统一筛选口径并通过完整台账保留关系,不能直接拼接各 GIS 输出声称范围一致。依据见第 5 节。 5. **缺坐标对象被几何输出静默丢弃。** 既有 GIS 使用判空后 continue/SQL IS NOT NULL,不能作为完整设施统计清单;新读模型应保留原始实体与校验理由,renderable 单独控制绘制。下拉 options 同样不是全字段来源。依据见第 4、5、6 节。另须明确分页/快照边界:现有业务 map adapter 签发后固定并缓存自身监测点/设备快照;分别调用现有 GIS/设施列表不会自动加入该版本,新几何接口不能仅回显同一 snapshotAt 就声称内容来自同一读取快照。[快照签发/缓存:105–172]()、[当前快照组成:198–274]()。 6. **线段与坐标系统边界。** 两端点字段只能表达直线;不能补造折线、中间节点、贴地形轨迹或真实连接拓扑。新读取路径逐端检验、整段聚合;考虑同点退化线、零端点、越界及 CRS 证据缺失。现验证器没有当地范围/退化线规则;新增规则必须作为新契约审定,不应冒充已有校验行为。依据见第 2、6 节。 7. **对象身份与删除边界。** PointId Long 与监测点 String ID、窨井 UUID 须加对象种类命名空间,关联表按自身删除策略处理;status=2 不能当 delFlag=2。直接 SQL 对每张可逻辑删除表显式限制正常值。独立排水模型不能继承本次统一设施字段/删除/CRS假设。依据见第 2、4、5 节。 8. **暴露面需单独复核。** 通用 GIS 读接口带 @Anonymous,燃气管点与窨井的关联新增/批量新增/删除也带 @Anonymous 且直接调用 mapper;源码可见缺少该方法级权限检查与关系存在性校验,但不能在未读取全部安全配置/数据库约束、未做请求验证时宣布实际可匿名越权。本次只建议独立安全复核,不执行调用。[通用 GIS:35–37、113–115、141–143]()、[管点关系写入:151–176]()、[窨井关系写入:101–126]()。 后续需要另行授权的验证项:实际部署 monitor_point.point_type 是否存在及现网值;燃气管点真实字典;三类设施坐标 CRS 与可信校核来源;networkId 外键/悬空/跨行业情况;逻辑删除实际 SQL。当前研究已给出可用源码依据,但没有执行这些运行时验证。