20 KiB
文档定位:
IT-1 运行时基座 M0第二轮开发的交付说明,与docs/公寓端/13表 13-11 /DV-1一一对应。 版本:v1.0 | 2026-11-10 环境:MySQLapt_rev01@127.0.0.1:3306(凭据由dev/.env注入)、Redis 本机database=1、JDK 24 / Maven 3.8.1 / Spring Boot 4.1.0 上位依据:公寓端/07表 7-2 / 7-3 / 7-6 / 7-8、公寓端/04§1 / §2 表 4-4、公寓端/03§4 表 3-12、公寓端/13表 13-11 / 13-21 / 13-22 / 13-30 / 13-32、公寓端/14表 14-23 权威关系:本文件是实现说明,不改变任何设计口径;阶段划分与验收仍以07为准,业务规则 / 状态 / 接口仍以 CR-02 §11~§15 为准;跨端仍 20 个编号、契约v2-draft、平台零回调、公寓本地库 59 张表均不变。
1. 交付概览与验收对照
表 15-1 第二轮交付物清单(对应 DV-1)
| 编号 | 交付物 | 落点 | 状态 |
|---|---|---|---|
| DV-1-1 | AptContext 增强(gyid/traceId/pageSize) |
ruoyi-common/.../apt/common/AptContext.java |
已交付 |
| DV-1-2 | 四前缀拦截器与解析器 | AptPrefixResolver.java、AptContextInterceptor.java、AptWebMvcConfig.java、SecurityConfig.java |
已交付,本轮补 /open/v1/** 放行 |
| DV-1-3 | 统一错误码与真实 HTTP 状态 | AptErrorCode.java、AptInfraExceptionHandler.java、AptAuthenticationEntryPoint.java、AptAccessDeniedHandler.java |
已交付,本轮补表 4-4 HTTP 列映射 |
| DV-1-4 | 审计切面落库 | AptAudit.java、AptAuditAspect.java、AptOperationLog.java、AptAuditMapper.java/.xml |
已交付,落 duty_operation_log |
| DV-1-5 | 分页封装(上限 100) | AptPageSupport.java、AptTableDataInfo.java、AptBaseController.java |
已交付 |
| DV-1-6 | 业务表只读查询骨架 | AptRoute.java、AptRouteMapper.java/.xml、AptRouteController.java |
已交付,不含 CRUD |
| DV-1-7 | springdoc 分组 | application.yml(apt/duty/open,扫 com.ruoyi.apt.**) |
已交付 |
| DV-1-8 | 权限点种子与 M0 验收账号 | dev/sql/apt_rev01/09_it1_permissions.sql |
已交付,二次执行幂等通过 |
| DV-1-9 | M0 用例脚本 | dev/scripts/verify-it1-m0.ps1 |
已交付,本轮端到端 5/5 通过 |
| DV-1-10 | 回归测试 | ruoyi-admin/src/test/java/com/ruoyi/apt/** |
41 用例全绿 |
| DV-1-11 | 本文档 | docs/公寓端/15 |
已交付 |
表 15-2 表 13-11 验收标准逐条对照
| # | 验收标准 | 依据 | 本轮结果 |
|---|---|---|---|
| 1 | 无令牌 /apt/route/list → 401 |
07 表 7-3 M0 |
通过:HTTP 401 + 40101/UNAUTHORIZED |
| 2 | 有令牌缺权限点 → 40301 | 07 表 7-3 M0 |
通过:HTTP 403 + 40301/PERMISSION_DENIED(apt_guest 角色) |
| 3 | gyid=A 查 gyid=B → 40302 且无数据泄露 |
07 表 7-3 M0、03 表 3-14 |
通过:HTTP 403 + 40302/GY_ID_CROSS_SCOPE,响应无 rows |
| 4 | 异常统一返回、无堆栈外泄 | 07 表 7-3 M0 |
通过:500 + {code,msg,data{reason,traceId,path}},无内部消息与堆栈 |
| 5 | pageSize=1000 截为 100 |
13 表 13-11(07 表 7-3 归 M1,本轮提前落地) |
通过:HTTP 200 + pageSize=100 |
| 6 | 架构测试断言所有业务 Mapper SQL 带 gyid |
13 表 13-11 |
通过:AptMapperGyidArchTest 扫描 mapper/apt/** |
表 15-3 前置条件与 Go-NoGo 状态
| 项 | 要求 | 状态 |
|---|---|---|
IT-0 契约冻结签字 |
13 表 13-10:未冻结不进 IT-1 |
未满足:14 表 14-22 ① 记「部分达成」,6 项 P0 与 IR-01 待冻结会签字;本轮按用户显式指令「继续下一轮开发」带条件开工,须补签 |
D5 一进程一 gyid 签字 |
13 表 13-24,拍板时点 IT-0 冻结会 |
未满足:代码已按 D5 实现(apt.gy-id 唯一来源),签字待补 |
| 数据库 / Redis | apt_rev01 59 表、Redis database=1 |
已具备,09_it1_permissions.sql 已执行且幂等 |
| 技术基线 | 设计锁定 JDK 1.8 / Boot 2.5.15,dev 实测 JDK 17 / Boot 4.1.0 |
IR-01 仍为 P0,实编译与运行均通过,定稿待冻结会 |
2. 模块职责边界与相互依赖关系
表 15-4 模块清单
| 层 | 包 / 文件 | 职责 | 明确不做 |
|---|---|---|---|
| 公共 | ruoyi-common com.ruoyi.apt.common |
gyid/traceId 上下文、错误码、异常、四前缀解析、分页封装、审计注解 |
不访问数据源、不碰若依 AjaxResult 语义 |
| 框架 | ruoyi-framework com.ruoyi.apt.framework |
拦截器注册、401/403 处理器、异常统一映射、审计切面、探针服务、AptProperties |
不写业务逻辑、不改若依 GlobalExceptionHandler 本体 |
| 系统 | ruoyi-system com.ruoyi.apt.master/ops |
只读列表 Domain/Mapper/XML、审计写入对象 | 不提供新增/编辑/删除/状态命令 |
| 启动 | ruoyi-admin com.ruoyi.apt.ops.controller |
自检接口(IT-0)+ 只读列表骨架(IT-1) | 不写入住/叫乘/账务业务 Controller |
| 配置 | SecurityConfig、application.yml、application-druid.yml |
过滤器链、springdoc 分组、数据源与 Redis | 凭据一律外置,不落明文 |
| SQL | 09_it1_permissions.sql |
只写 sys_* 框架表的权限点种子 |
不触碰 59 张业务表 |
图 15-1 依赖方向
flowchart LR
A["SecurityConfig / 过滤器链"] --> B["AptAuthenticationEntryPoint<br/>AptAccessDeniedHandler"]
A --> C["AptContextInterceptor"]
C --> D["AptPrefixResolver"]
C --> E["AptContext"]
C --> F["AptProperties (apt.gy-id)"]
G["AptRouteController"] --> H["AptBaseController"]
H --> I["AptPageSupport / AptTableDataInfo"]
G --> J["AptRouteMapper (gyid 隔离)"]
G --> K["@AptAudit → AptAuditAspect"]
K --> L["AptAuditMapper → duty_operation_log"]
M["AptInfraExceptionHandler"] --> E
M --> N["AptErrorCode"]
拦截器在 preHandle 写入 gyid 与 traceId,afterCompletion 清理;业务 Controller 只从 AptContext 取值,绝不采信请求参数。
3. 四前缀治理与鉴权
表 15-5 四前缀策略矩阵(04 §1、13 表 13-11)
| 前缀 | 会话要求 | 附加校验 | 拒绝码 | 过滤器链 |
|---|---|---|---|---|
/apt/** |
需登录(@Anonymous 例外) |
参数/头 gyid 与配置一致性 |
40101 / 40302 |
anyRequest().authenticated() |
/duty/** |
需登录(@Anonymous 例外) |
同上 | 40101 / 40302 |
anyRequest().authenticated() |
/open/v1/** |
匿名分区 | 必填 X-Device-Code;gyid 不一致 → 40303 |
40101 / 40303 |
本轮补 permitAll(),否则会被提前 401 |
/platform/** |
本端不提供 | 有令牌也显式拒绝 | 40401 PREFIX_NOT_SERVED |
anyRequest().authenticated() |
设备侧 HMAC / 时间窗 / nonce 完整校验在
IT-3落地;本轮只做占位骨架,符合表 13-11「不含业务表 CRUD」。
表 15-6 权限点种子(09_it1_permissions.sql)
| menu_id | 权限点 | 本轮状态 |
|---|---|---|
| 3000 | 公寓端父目录 | 启用 |
| 3001 | apt:route:list |
启用,关联超管角色 1(留痕) |
| 3002 | apt:ops:connectivity |
仅登记(自检接口为 @Anonymous) |
| 3003~3006 | apt:room:list、apt:jcxx:list、duty:checkin:list、apt:ledger:local |
置灰不关联角色(13 表 13-29 预埋不上线) |
| 角色 300 / 账号 300 | apt_guest |
M0「有令牌缺权限点」验收账号,apt_permission_count=0;生产部署前必须删除 |
表 15-7 统一错误响应
| 场景 | HTTP | body |
|---|---|---|
| 未登录(过滤器链) | 401 | {code:40101, msg, data:{reason:"UNAUTHORIZED", traceId, path}} |
权限不足(过滤器链 / @PreAuthorize) |
403 | {code:40301, msg, data:{reason:"PERMISSION_DENIED", traceId, path}} |
| 跨公寓 / 前缀拒绝 / 参数非法 | 按表 4-4 | {code, msg, data:{reason, traceId, path}} |
| 未知异常(公寓端四前缀) | 500 | msg 固定为「内部错误(已记录)」,不回传 e.getMessage() 与堆栈 |
| 非公寓端路径 | 保持若依原状 | 401 委托 AuthenticationEntryPointImpl;403 委托 AccessDeniedHandlerImpl;ServiceException 保留自定义 code |
4. 接口与错误码约定
表 15-8 本轮接口清单
| 方法 | 路径 | 权限点 | 请求参数 | 返回结构 | 错误码 |
|---|---|---|---|---|---|
| GET | /apt/route/list |
apt:route:list |
cc、jlid、state、pageNum/pageSize、orderByColumn/isAsc |
{code,msg,rows,total,pageSize,traceId} |
40101、40301、40302、500 |
| GET | /apt/ops/connectivity |
@Anonymous + 仅回环 |
无 | {code,msg,data{overall,gyid,results[],traceId}} |
40001、40301、50301/50304 |
| POST | /apt/ops/connectivity/probe |
@Anonymous + 仅回环 |
{target:"DB|REDIS|ALL", strict:bool} |
同上 | 40001 INVALID_TARGET、50301、50304 |
| GET | /apt/ops/connectivity/error-probe |
@Anonymous + 仅回环 |
无 | 统一错误体 | 500 UNEXPECTED_ERROR |
| — | springdoc /v3/api-docs?group=apt|duty|open |
匿名 | — | 分组文档 | — |
/platform/**不分组(公寓端不提供);/apt/route/list为只读骨架,表 13-11 明确本轮不含 CRUD。
表 15-9 AptErrorCode 与表 4-4 HTTP 列映射(本轮补齐)
| 段 | 码 | HTTP | 典型场景 |
|---|---|---|---|
| 参数 | 40001 |
400 | 必填缺失、target 非法 |
| 认证 | 40101 |
401 | 无令牌、令牌失效、设备凭据缺失 |
| 授权 | 40301/40302/40303 |
403 | 缺权限点、跨公寓、设备跨公寓 |
| 不存在 | 40401 |
404 | 对象不存在、/platform/** 前缀拒绝 |
| 冲突 | 40901~40916、40940 |
409 | 重复键、状态非法、延后域预埋 |
| 其他 | 41001、50101/50102、50301/50302/50304、500 |
410/501/503/500 | 录音清理、协议未定、依赖不可用、数据异常、兜底 |
50304(数据异常)为 IT-0 在既有503xx段内新增,40940为 CR-02 表 C-3 延后域预埋;二者须随50304一并纳入契约冻结登记,40940本期不启用。
表 15-10 异常策略矩阵
| 异常 | 映射 | 对外可见信息 |
|---|---|---|
AptException |
自身 AptErrorCode + reason |
仅 msg / reason / traceId / path |
AccessDeniedException(公寓端) |
40301 |
同上 |
ServiceException(公寓端) |
40001 SERVICE_EXCEPTION |
不外泄原始 message |
ServiceException(非公寓端) |
若依原 code / message |
保持上游行为 |
DuplicateKeyException / DataIntegrityViolationException |
40901 / 50304 |
无堆栈 |
CannotGetJdbcConnectionException / QueryTimeoutException / Redis* |
50301 |
无连接串、无凭据 |
兜底 Exception(四前缀内) |
500 UNEXPECTED_ERROR |
仅写日志,不回传 e.getMessage() |
5. 审计与分页
表 15-11 审计落库字段(duty_operation_log)
| 字段 | 来源 | 说明 |
|---|---|---|
gyid |
AptContext.getGyIdOrNull(),缺失写 UNKNOWN |
强制隔离列,AptAuditMapper.xml INSERT 必带 |
log_id |
UUID(去横线) | 与 gyid 组成唯一键 |
operator_ref |
SecurityUtils.getLoginUser(),异常时 ANONYMOUS |
— |
module / action |
@AptAudit 注解 |
如 ROUTE / LIST |
detail |
JSON | status、costMs、traceId、uri、httpMethod、params(敏感键过滤) |
trace_id / occurred_at |
AptContext / 当前时间 |
与错误响应可关联 |
与若依
@Log/sys_oper_log并行,不改上游表;写库失败只 WARN,不影响业务返回。审计写入当前与业务同事务,IT-2引入写操作后需评估REQUIRES_NEW,避免事务回滚时丢留痕。
表 15-12 分页规则
| 项 | 规则 |
|---|---|
| 硬上限 | AptPageSupport.HARD_MAX_SIZE = 100,配置 apt.page.max-size 高于此值仍被压制 |
| 默认值 | pageNum=1、pageSize=10;pageSize<=0 回落默认 |
| 生效链路 | AptBaseController.startAptPage() → AptPageSupport.startPage() → PageHelper.startPage() |
| 响应回显 | AptTableDataInfo 追加 pageSize 与 traceId |
| 排序 | 只读列表固定 ORDER BY state DESC, kcsj ASC, cc ASC,禁止默认按 id(04 §1.2) |
6. 验证结果
表 15-13 本轮实际执行的验证
| # | 验证项 | 手段 | 结果 |
|---|---|---|---|
| 1 | 全量编译与打包 | mvn -B -ntp package(JDK 24 / Maven 3.8.1) |
7 模块 BUILD SUCCESS,ruoyi-admin.jar 重打包 |
| 2 | 全量单测 | Surefire 3.5.2 + JUnit5 | Tests run: 41, Failures: 0, Errors: 0 |
| 3 | 四前缀 / 鉴权 | AptPrefixResolverTest、AptAuthInterceptorTest、AptAccessDeniedHandlerTest |
通过 |
| 4 | 错误码 / 异常 | AptErrorResponseTest、AptInfraExceptionHandlerTest、AptConnectivityControllerTest |
通过(含真实 HTTP 状态 400/403/503) |
| 5 | 审计落库 | AptAuditAspectTest(成功/失败/写库降级/敏感过滤) |
通过 |
| 6 | 分页 | AptPageSupportTest(normalize + 真实 PageHelper 链路) |
通过 |
| 7 | Mapper 架构约束 | AptMapperGyidArchTest(gyid + 非 id 排序) |
通过 |
| 8 | 权限点种子 | 09_it1_permissions.sql 首次/二次执行 |
幂等通过,apt_permission_count=0;追加置灰/总数/账号状态校验 SELECT |
| 9 | 静态检查 | read_lints(com.ruoyi.apt.** 与 SQL) |
0 错误 |
| 10 | 真实进程端到端 M0 | dev/scripts/verify-it1-m0.ps1,启动 ruoyi-admin.jar + 真实 HTTP |
5/5 通过(见表 15-14) |
表 15-14 端到端 M0 实测(07 表 7-3 M0 四项 + 13 表 13-11 扩展两项)
| 用例 | 期望 | 实测 |
|---|---|---|
无令牌 /apt/route/list |
HTTP 401 / 40101 |
HTTP 401 / 40101 |
apt_guest 有令牌缺权限点 |
HTTP 403 / 40301 |
HTTP 403 / 40301 |
令牌 gyid=A 查 gyid=B |
HTTP 403 / 40302,无数据 |
HTTP 403 / 40302,响应无 rows |
/apt/ops/connectivity/error-probe |
统一错误体、无堆栈外泄 | 500 + data.traceId,无内部标记与堆栈 |
pageSize=1000 |
截为 100 | HTTP 200 + pageSize=100 |
端到端脚本从
dev/.env加载凭据,经/captchaImage+ Redisdatabase=1的captcha_codes:<uuid>读取验证码答案完成登录,未关闭验证码开关、未修改sys_config;结束后自动停止应用进程。 环境发现:dev/.env的APT_TOKEN_SECRET仍是占位文本,而TokenService.signWith(HS512, secret)要求 Base64 编码且解码后 ≥64 字节,否则登录抛ArrayIndexOutOfBoundsException。脚本已内置「本次运行生成临时密钥」兜底,.env未改动;本轮修正了dev/.env.example中误导性的APT_TOKEN_SECRET提示(原文引导填 hex 文本),改为 Base64 要求与生成示例,并补齐从application*.yml提取的变量;本机.env仍须按模板填写。
7. 口径偏离与待评审项
表 15-15 口径偏离登记(含任务 1 核对结果与本轮处置)
| # | 偏离 | 本轮处置 | 待办 |
|---|---|---|---|
| 1 | 契约冻结签字未完成即开工 | 按用户显式指令带条件开工,交付说明显式登记 | 补冻结会签字(P0) |
| 2 | gyid 注入:表 13-11 写「只从会话/设备凭据解析」、03 表 3-12 写「令牌声明 → AptContext」,实现按 D5 只从 apt.gy-id 配置注入 |
请求参数/头仅作一致性校验并拒绝跨域 | 随 D5 签字确认口径 |
| 3 | M0「令牌 gyid=A 查 gyid=B」在 D5 下无令牌态 gyid |
验收改为「参数/头 gyid 不一致 → 40302/40303」(03 表 3-14 用例 2 允许) |
验收脚本已固化,冻结会确认 |
| 4 | 分页上限归 M1(07 表 7-3),表 13-11 提前并入 IT-1 |
已提前实现并验证 | 交付记录按 6 项 |
| 5 | 表 4-4 外的错误码 50304 / 40940 / 500 |
50304 沿用 503xx 段、40940 属 CR-02 预埋、500 仅兜底 |
50304 纳入冻结登记;40940 本期不启用 |
| 6 | 审计切面实现为独立 @AptAudit 而非「扩展 @Log」 |
落 duty_operation_log,与若依 @Log 并行、不改上游表 |
登记即可 |
| 7 | AptAccessDeniedHandler / handleAccessDenied 曾越界改变若依后台 403 |
本轮已修:非公寓端分别委托 AccessDeniedHandlerImpl 与若依原 code |
已完成 |
| 8 | /open/v1/** 曾被 anyRequest().authenticated() 提前 401 |
本轮已修:SecurityConfig 放行,由拦截器校验 X-Device-Code |
IT-3 补 HMAC |
| 9 | AptException 曾一律 HTTP 200,与表 4-4 不符 |
本轮已修:applyHttpStatus 按码前三位映射,并同步更新 IT-0 自检用例断言 |
已完成 |
| 10 | ServiceException 被 @Order(HIGHEST_PRECEDENCE) 吞掉自定义 code |
本轮已修:新增专门 handler,非公寓端保留若依口径 | IT-2 需补 BindException / MethodArgumentNotValidException 类型分派 |
| 11 | 只读骨架字段与 04 表 4-5 不同(state/route_name/... vs enabled/jch/qd/jcsj/...) |
apt_master_route 为 IT-0 [推断] 表,骨架按 DDL 实现 |
IT-2 交路 CRUD 前给出字段映射,不改 59 张表设计口径 |
| 12 | 只读骨架 Controller 暂落 com.ruoyi.apt.ops.controller |
表 13-21 要求交路域落 com.ruoyi.apt.master.* |
IT-2 迁移 |
| 13 | 表 13-11/13-22 引用「03 §5 四级隔离」 |
实际四级隔离在 03 §4 表 3-12,§5 为逻辑删除约定 |
文档交叉引用待勘误 |
| 14 | application.yml 的 token.secret 与 .env 占位文本不兼容 |
验收脚本内置临时 Base64 兜底 | 修正本机 .env;run-local.ps1 未内置兜底 |
8. 变更点与影响范围、后续衔接
表 15-16 变更点与影响范围
| 类别 | 变更 | 影响范围 |
|---|---|---|
| 新增 | AptPrefixResolver、AptAudit+切面+Mapper、AptPageSupport/AptTableDataInfo、AptBaseController、401/403 处理器、只读列表骨架、09_it1_permissions.sql、verify-it1-m0.ps1、本文档 |
dev/RuoYi-Vue-master 后端、dev/sql/apt_rev01、dev/scripts、文档索引 |
| 修改 | SecurityConfig(/open/v1/** 放行 + 401/403 处理器)、application.yml(springdoc 三组)、AptContext(pageSize)、AptErrorCode(表 4-4 全量)、AptInfraExceptionHandler(HTTP 状态 + ServiceException)、AptConnectivityController(error-probe)、dev/.env.example |
若依启动链路与非公寓端路径行为已做前缀隔离,后台管理保持原行为 |
| 测试 | 32 → 41 用例;IT-0 自检用例断言改为真实 HTTP 400/403/503 | ruoyi-admin 构建 |
| 不变 | CR-02 §12~§15 权威表述、跨端 20 编号、v2-draft、平台零回调、公寓本地库 59 张表、apt.duty.state 单写入口、统计结果不回写、F-AF-Q、Q-01 |
无设计口径改动;未新增 M7 / 阶段六 / D-4 / Q-* / R-* / 施工单编号 |
| 提交纪律 | 本轮未执行 git commit / git push |
变更清单待评审 |
表 15-17 后续衔接(IT-2 主数据与房间)
| 项 | 内容 |
|---|---|
| 前置 | 本轮 M0 六项全过;D8' / D3 / D7 签字;表 15-15 #11 / #12 的字段映射与包迁移 |
| 范围 | 交路 CRUD + 复算校验 + 启停原因、房间档案 + 房态 + state_version、#1~#4 主数据下行 Mock(source='LOCAL') |
| 需补 | BindException / MethodArgumentNotValidException 的非公寓端类型分派;审计写入独立事务;只读骨架 Controller 迁入 com.ruoyi.apt.master.* |
| 回归 | 表 7-3 M1/M2、表 7-6 八类用例 M0~M2 部分;本文件表 15-14 的 M0 五项须持续全绿 |
| 延后 | IT-9~IT-11 消费 / 充值 / 菜品,本期不开 /apt/ledger/**、不建 com.ruoyi.apt.ledger 包 |