1 parent
329e27b515
commit
8ffeb59dd4
33 files changed
+3427
-111
No files matched your search
@@ -0,0 +1,406 @@
|
||||
> **文档定位**:`IT-0 基线对齐与契约冻结` 第一轮开发的交付说明,与 `docs/公寓端/13` 表 13-10 / `DV-0` 一一对应。
|
||||
> **版本**:v1.0 | 2026-11-10
|
||||
> **环境**:MySQL `apt_rev01` @ `127.0.0.1:3306`(凭据由环境变量注入)、Redis 本机 `database=1`
|
||||
> **上位依据**:`docs/10` §9、`公寓端/07` 表 7-1~7-8、`公寓端/03` 表 3-8~3-15、CR-02 表 3-25 / 3-27~3-33、`公寓端/13` 表 13-4 / 13-6 / 13-10 / 13-21
|
||||
> **权威关系**:本文件是**实现说明**,不改变任何设计口径;阶段划分与验收仍以 `07` 为准,业务规则 / 状态 / 接口仍以 CR-02 §11~§15 为准。
|
||||
|
||||
---
|
||||
|
||||
## 1. 交付概览与口径偏离登记
|
||||
|
||||
表 14-1 第一轮交付物清单(对应 `DV-0`)
|
||||
|
||||
| 编号 | 交付物 | 落点 | 状态 |
|
||||
| --- | --- | --- | --- |
|
||||
| DV-0-1 | 分域增量 DDL(59 张业务表 + 1 张探针表) | `dev/sql/apt_rev01/00`~`06` | 已交付并在 `apt_rev01` 实际执行 |
|
||||
| DV-0-2 | 幂等补列脚本 / 可重放种子 / 验收校验脚本 | `dev/sql/apt_rev01/07`、`08`、`99` | 已交付并二次执行验证 |
|
||||
| DV-0-3 | 数据源与 Redis 连接配置、凭据外置 | `application-druid.yml`、`application.yml`、`.gitignore`、`dev/.env.example` | 已交付 |
|
||||
| DV-0-4 | 基座模块(错误码 / 上下文 / 拦截器 / 异常映射 / 探针服务) | `ruoyi-common`、`ruoyi-framework` 的 `com.ruoyi.apt.**` | 已交付 |
|
||||
| DV-0-5 | 连通性自检接口(非业务 Controller) | `ruoyi-admin` 的 `com.ruoyi.apt.ops.controller` | 已交付 |
|
||||
| DV-0-6 | 测试骨架(JUnit5 + MockMvc + Mockito) | `ruoyi-admin/src/test/java/com/ruoyi/apt/**`、`maven-surefire-plugin` | 12 用例全绿 |
|
||||
| DV-0-7 | CI 工作流(编译 / 单测 / 明文凭据扫描) | `.github/workflows/it0-verify.yml` | 已交付 |
|
||||
| DV-0-8 | 本地启动脚本 | `dev/scripts/run-local.ps1` | 已交付 |
|
||||
|
||||
表 14-2 口径偏离与待评审项(须阶段二冻结评审签字)
|
||||
|
||||
| 项 | 设计口径 | 本轮实际 | 处置 |
|
||||
| --- | --- | --- | --- |
|
||||
| DDL 执行时点 | 待阶段二契约冻结后执行 | 按用户显式指令在 `IT-0` 预执行 | 登记偏离;脚本幂等可重放,冻结后如调整列由 `07` 增量补齐 |
|
||||
| 业务 Controller | `R-02` 冻结前不写 Controller | 只写**运维自检接口**,无任何入住 / 叫乘 / 账务业务 Controller | 不算偏离;自检接口属基座连通性验证 |
|
||||
| 33 张表字段 | 文档只有表名 / owner,无列级定义 | 按接口契约与表 3-9/3-15 通用规则**推断补齐**,注释标 `[推断]` | 待 `Q-20` / `Q-40` / `Q-43` 冻结评审确认 |
|
||||
| 错误码 `50304` | 表 4-4 未列 | 在既有 `503xx` 段内新增「数据异常」 | 沿用 CR-02 同段追加做法,需冻结评审登记 |
|
||||
| 技术基线 | 设计锁定 JDK 1.8 / Boot 2.5.15;`dev` 实测 JDK 17 / Boot 4.1.0 | 本机 `JAVA_HOME` 为 JDK 24(PATH 中另有 JDK 8),Maven 3.8.1,**实编译通过** | `IR-01` 仍为 P0 决策项,须冻结会定稿 |
|
||||
| 平台统计表 | `pl_apt_stat_*` 待 `Q-48` 冻结 | 本轮**不建**(平台库不在本轮范围) | 与表 13-29 一致 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 功能模块职责边界与相互依赖关系
|
||||
|
||||
表 14-3 模块清单
|
||||
|
||||
| 模块 | 代码落点 | 职责(做什么) | 边界(不做什么) | 依赖 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `apt-common` | `ruoyi-common/com.ruoyi.apt.common` | `AptErrorCode` 错误码、`AptException`、`AptContext`(gyid + traceId) | 不依赖 Web / JDBC / Redis;不读配置 | 无 |
|
||||
| `apt-config` | `ruoyi-framework/com.ruoyi.apt.framework.config` | `AptProperties` 绑定 `apt.*`(gyid、探针超时、key 前缀、TTL、分页上限) | 不写业务规则 | Spring Boot |
|
||||
| `apt-web` | `ruoyi-framework/com.ruoyi.apt.framework.web` | `AptContextInterceptor` 注入 gyid/traceId、`AptWebMvcConfig` 注册 `/apt/**`、`AptInfraExceptionHandler` 统一异常映射 | 不采信请求参数中的 gyid;不外泄堆栈;本轮只注册 `/apt/**` | `apt-common`、`apt-config` |
|
||||
| `apt-infra.connectivity` | `ruoyi-framework/com.ruoyi.apt.infra.connectivity` | `AptConnectivityService` DB/Redis 连通性 + 读写闭环、`ProbeResult` 结构化结果 | **只操作探针表 `apt_ops_probe` 与探针 key**,不碰 59 张业务表;不产生业务数据 | `DataSource`、`StringRedisTemplate`、`apt-config`、`apt-common` |
|
||||
| `apt-ops` | `ruoyi-admin/com.ruoyi.apt.ops.controller` | 自检接口:参数校验、结果组装、strict 错误码、回环访问控制 | 不提供任何业务接口 | 上述全部 |
|
||||
| `sql/apt_rev01` | `dev/sql/apt_rev01/*.sql` | 59 张业务表结构、幂等补列、可重放种子、验收校验 | DDL 与回填分离;不建外键;不含真实凭据 | MySQL 9.5 |
|
||||
| `ci` | `.github/workflows/it0-verify.yml` | 编译 / 单测 / 明文凭据扫描卡口 | 不执行 DDL、不连生产库 | GitHub Actions |
|
||||
|
||||
图 14-1 模块依赖(单向,无环)
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["apt-common<br/>错误码 / 上下文"] --> B["apt-config<br/>配置绑定"]
|
||||
A --> C["apt-web<br/>拦截器 / 异常映射"]
|
||||
B --> C
|
||||
A --> D["apt-infra.connectivity<br/>DB / Redis 探针"]
|
||||
B --> D
|
||||
C --> E["apt-ops<br/>自检接口"]
|
||||
D --> E
|
||||
F["DataSource Druid<br/>MySQL apt_rev01"] --> D
|
||||
G["StringRedisTemplate<br/>Redis database=1"] --> D
|
||||
H["sql/apt_rev01<br/>59 张业务表"] --> F
|
||||
```
|
||||
|
||||
表 14-4 模块间调用关系与依赖顺序
|
||||
|
||||
| 顺序 | 依赖对 | 约束 |
|
||||
| --- | --- | --- |
|
||||
| 1 | `sql` → `DataSource` | 先建表再启动应用;`SELECT 1` 可在无表时通过,但读写探针需 `apt_ops_probe` |
|
||||
| 2 | `apt-common` → 全部 | 错误码与 gyid 上下文是统一异常映射的前置 |
|
||||
| 3 | `apt-config` → `apt-web` / `apt-infra` | gyid 只能来自配置,不能来自请求 |
|
||||
| 4 | `apt-web`(拦截器)→ `apt-ops` | 缺 gyid 时 `AptContext.getGyId()` 抛 `40302`,接口不可降级 |
|
||||
| 5 | `apt-infra` → `apt-ops` | 探针失败先落 `ProbeResult`,由控制器按 `strict` 决定是否交给异常处理器 |
|
||||
| 6 | `apt-web`(异常处理器)← `apt-ops` | 所有 `AptException` / `DataAccessException` 统一转 `{code,msg,data{reason,traceId,path}}` |
|
||||
|
||||
> **与表 13-21 的对齐**:第一轮基座(infra)落 `ruoyi-framework` 而非 `ruoyi-system`,因为 framework 已依赖 system + 数据源 + Redis,可避免反向依赖;`IT-1` 起的业务域包仍按表 13-21 落 `ruoyi-system` 的 `com.ruoyi.apt.*`。未新建任何 Maven 模块,唯一启动 jar 仍为 `ruoyi-admin`。
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据表结构设计
|
||||
|
||||
### 3.1 总体口径
|
||||
|
||||
表 14-5 通用列与约束规则
|
||||
|
||||
| 规则 | 内容 | 依据 |
|
||||
| --- | --- | --- |
|
||||
| 引擎 / 字符集 | `InnoDB` + `utf8mb4` + `utf8mb4_0900_ai_ci` | MySQL 9.5 |
|
||||
| 主键 | 全部使用代理主键 `id BIGINT NOT NULL AUTO_INCREMENT`,`PRIMARY KEY(id)` | CR-02 表 3-26、表 3-33 |
|
||||
| 唯一键 | 业务幂等键一律 `UNIQUE KEY` 且**以 `gyid` 打头**,多租户隔离 | 公寓端/03 表 3-15、CR-02 表 3-33 |
|
||||
| 外键 | **0 个**(`99_verify.sql` 第 5 项校验为 0);跨端 / 分库场景由应用层约束 + 对账兜底 | `docs/10` 表 5-6 |
|
||||
| 状态列 | `VARCHAR` 大写下划线枚举 + `CHECK` 约束;不用 MySQL `ENUM`、不用数字码 | CR-02 表 3-26 |
|
||||
| 金额 / 比率 / 时间 | `DECIMAL(12,2)` / `DECIMAL(10,2)` / `DATETIME(3)`;禁止浮点 | `docs/10` 表 5-4 |
|
||||
| 审计列 | `deleted TINYINT NOT NULL DEFAULT 0`、`create_time`、`update_time` | 表 3-15 |
|
||||
| 单写入口 | `gy_jcxx` 的 `ryzt/finish_jc/finish_ly/stoped` 仅 `apt.duty.state` 可写;`gy_rooms.room_status` 仅 `apt-stay` 可写 | CR-02 表 3-33、表 13-10 |
|
||||
| 乐观锁 | `biz_version` / `state_version` / `config_version` / `balance_version`,语义互不混用 | CR-02 表 3-26 |
|
||||
| 三时间戳 | `occurred_at`(业务发生)、`received_at`(本地入库)、`platform_recv_at`(归日依据) | §15 |
|
||||
| 幂等 | 全部 `CREATE TABLE IF NOT EXISTS`;补列走 `apt_add_column_if_missing`;种子 `WHERE NOT EXISTS` | 表 13-10 验收③ |
|
||||
|
||||
### 3.2 59 张业务表清单(按域,完整字段定义见 `dev/sql/apt_rev01/*.sql`)
|
||||
|
||||
表 14-6 域 1:主数据 / 计划 / 本地建单(11 张,`01_domain_01_master.sql`)
|
||||
|
||||
| # | 表名 | 主键 | 唯一键(UK) | 主要索引(IDX) | 关键列 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | `apt_master_version` | id | (gyid,domain) | (gyid,state,applied_at) | source_version, source=PLATFORM/LOCAL |
|
||||
| 2 | `apt_master_apartment` | id | (gyid,apartment_code) | — | apartment_name, state |
|
||||
| 3 | `apt_master_room` | id | (gyid,room_id) | (gyid,room_floor,room_no) | room_floor, building(Q-20 未启用), state_version, source_version |
|
||||
| 4 | `apt_master_person` | id | (gyid,ryid) | (gyid,work_no),(gyid,xm) | photo_ref/feature_ref 只存引用, face_sync_state |
|
||||
| 5 | `apt_master_route` | id | (gyid,jlid) | (gyid,cc,kcsj) | cc, kcsj, state=ACTIVE/STOPPED |
|
||||
| 6 | `apt_master_rule` | id | (gyid,rule_id,rule_version) | (gyid,rule_type,state) | rule_body JSON |
|
||||
| 7 | `apt_holiday` | id | (gyid,holiday_date) | — | holiday_type |
|
||||
| 8 | `gy_syn_jcxx` | id | (gyid,jcid) | (gyid,jlid,jcsj) | jcsj 仅基线, computed_jcsj 权威 |
|
||||
| 9 | `gy_syn_jcxx_status` | id | (gyid,jcid) | (gyid,sync_state,last_sync_at) | retry_count, error_code |
|
||||
| 10 | `gy_call_duty_match_lock` | id | (gyid,lock_key) | (gyid,lease_until) | lease_until, owner_ref |
|
||||
| 11 | `apt_local_task` | id | (gyid,task_id),(gyid,jcid) | (gyid,apply_id),(gyid,match_state,checkin_state) | match_state / checkin_state / sync_state 三状态链, request_payload JSON(Q-40 兜底) |
|
||||
|
||||
表 14-7 域 2:执行 / 设备(11 张,`02_domain_02_exec_device.sql`)
|
||||
|
||||
| # | 表名 | 主键 | 唯一键(UK) | 主要索引(IDX) | 关键列 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 12 | `gy_jcxx` | id | (gyid,jcid) | (gyid,jcsj),(gyid,ryzt,finish_ly),(gyid,dispatch_seq) | ryzt 0~5, finish_jc/finish_ly/stoped, sjlysj, call_mode, biz_version, 三时间戳 |
|
||||
| 13 | `gy_jcxx_his` | id | (gyid,jcid) | (gyid,archived_at) | summary_payload JSON(satisfaction / roomOccupancy) |
|
||||
| 14 | `gygl_ly_event` | id | (gyid,event_id) | (gyid,event_type,occurred_at) | event_type, event_source, report_state 五值 |
|
||||
| 15 | `gy_rooms` | id | (gyid,room_id) | (gyid,room_status,room_floor) | room_status 1~6, state_version |
|
||||
| 16 | `gy_clean_task` | id | (gyid,task_id) | (gyid,state,scheduled_at) | state, assignee_ref |
|
||||
| 17 | `gy_bjxx` | id | (gyid,alarm_id) | (gyid,alarm_type,occurred_at),(gyid,handled_at) | handled_at, biz_version |
|
||||
| 18 | `gy_bjcstj` | id | (gyid,stat_date) | — | alarm_count, handled_count |
|
||||
| 19 | `gy_sb` | id | (gyid,device_code) | (gyid,device_type,state) | face_scope_type/ref(§12 补列) |
|
||||
| 20 | `gy_sb_xt` | id | (gyid,device_code) | (gyid,online_state,heartbeat_at) | online_state |
|
||||
| 21 | `gy_sb_zl` | id | (gyid,command_id) | — | 只读存量兼容 |
|
||||
| 22 | `apt_device_command` | id | (gyid,command_id) | (gyid,state,create_time) | state, protocol_confirmed 默认 0 |
|
||||
|
||||
表 14-8 域 3:语音(12 张,`03_domain_03_voice.sql`)
|
||||
|
||||
| # | 表名 | 主键 | 唯一键(UK) | 主要索引(IDX) | 关键列 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 23 | `apt_sip_endpoint` | id | (gyid,endpoint_id),(gyid,extension) | (gyid,sync_state) | extension 大写, config_version, sync_state 四值 |
|
||||
| 24 | `apt_sip_binding` | id | (gyid,binding_id) | (gyid,room_id,state) | effective_from/to |
|
||||
| 25 | `apt_trunk` | id | (gyid,trunk_id) | — | host_ref 只存引用 |
|
||||
| 26 | `apt_call_session` | id | (gyid,session_id) | (gyid,jcid),(gyid,call_state,started_at) | conf_no 不加唯一约束, answered_at |
|
||||
| 27 | `apt_call_event` | id | (gyid,event_id),(gyid,session_id,event_seq) | (gyid,occurred_at) | 只追加 |
|
||||
| 28 | `apt_call_event_his` | id | (gyid,event_id) | (gyid,archived_at) | 只读 |
|
||||
| 29 | `apt_recording` | id | (gyid,recording_id) | (gyid,session_id) | file_ref 只存引用, state 四值 |
|
||||
| 30 | `apt_tts_utterance` | id | (gyid,utterance_id) | — | audio_ref |
|
||||
| 31 | `apt_ast_config_version` | id | (gyid,version_id) | — | checksum, applied_at |
|
||||
| 32 | `apt_ast_drift` | id | (gyid,drift_id) | (gyid,state,detected_at) | expected_ref / actual_ref |
|
||||
| 33 | `apt_ast_ami_session` | id | (gyid,ami_session_id) | (gyid,state,connected_at) | reconnect_count |
|
||||
| 34 | `apt_sip_reg_status` (T-17) | id | (gyid,endpoint_id,event_seq) | (gyid,state,occurred_at),(gyid,endpoint_id,occurred_at) | 只追加、无 update_time、state 四值 / source 五值 |
|
||||
|
||||
表 14-9 域 4:账务(6 张,`04_domain_04_ledger.sql`,**预埋不上线**)
|
||||
|
||||
| # | 表名 | 主键 | 唯一键(UK) | 主要索引(IDX) | 关键列 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 35 | `gy_ykt_remainder` | id | (gyid,ryid) | — | knye/xjye 双额度, balance_version, local_balance_version |
|
||||
| 36 | `gy_ykt_consume` | id | (gyid,flow_id),(gyid,device_event_id) | (gyid,occurred_at) | allowance_amount, cash_amount, ledger_state |
|
||||
| 37 | `gy_ykt_allowance` | id | (gyid,allowance_id) | (gyid,ryid,issue_at) | amount, period |
|
||||
| 38 | `gy_ykt_cash_request` | id | (gyid,request_id) | (gyid,request_state,create_time) | **申请表不存金额** |
|
||||
| 39 | `gy_ykt_xjczjl` | id | (gyid,flow_id) | (gyid,occurred_at) | amount 正数计收入 |
|
||||
| 40 | `apt_ledger_offline` (T-11) | id | (gyid,type,flow_id) | (gyid,reconcile_state,occurred_at) | balance_before/after, idempotency_key, offline_scope |
|
||||
|
||||
表 14-10 域 5:上报 / 值班 / 运维(11 张,`05_domain_05_report_duty_ops.sql`)
|
||||
|
||||
| # | 表名 | 主键 | 唯一键(UK) | 主要索引(IDX) | 关键列 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 41 | `apt_report_outbox` | id | (gyid,idempotency_key) | (gyid,state,watermark),(gyid,biz_type,biz_id) | **队列态** 五值, retry_batch_id, watermark |
|
||||
| 42 | `apt_report_watermark` | id | (gyid) | — | current/acked_watermark, clock_skew_ms |
|
||||
| 43 | `duty_operation_log` | id | (gyid,log_id) | (gyid,occurred_at),(gyid,trace_id) | detail JSON 兜底 |
|
||||
| 44 | `duty_manual_action` | id | (gyid,action_id) | (gyid,jcid,occurred_at) | duplicated 标志 |
|
||||
| 45 | `duty_shift_handover` | id | (gyid,handover_id) | (gyid,handed_at) | content JSON |
|
||||
| 46 | `apt_ops_selfcheck` | id | (gyid,check_id) | (gyid,checked_at) | 12 项自检定义 |
|
||||
| 47 | `apt_person_account` | id | (gyid,ryid) | — | sys_user_id |
|
||||
| 48 | `apt_report_history` (T-09) | id | (gyid,idempotency_key) | (gyid,state,sent_at) | **终态流水**,与 outbox 不互换 |
|
||||
| 49 | `apt_report_retry_batch` (T-10) | id | (gyid,batch_id) | — | trigger_type, from/to_watermark |
|
||||
| 50 | `duty_roster` (T-12) | id | (gyid,shift_id,ryid) | (gyid,shift_date) | shift_type DAY/NIGHT |
|
||||
| 51 | `duty_performance` (T-13) | id | (gyid,stat_date,ryid) | (gyid,stat_date) | 本地算、平台汇总 |
|
||||
|
||||
表 14-11 域 6:CR-02 新增业务表(8 张,`06_domain_06_cr02_extra.sql`)
|
||||
|
||||
| # | 表名 | 主键 | 唯一键(UK) | 主要索引(IDX) | 关键列 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 52 | `apt_tablet_device` (T-01) | id | (gyid,device_code) | — | activation_code_ref, register_status |
|
||||
| 53 | `apt_tablet_task` (T-02) | id | (gyid,task_id) | (gyid,dispatch_seq),(gyid,jcsj) | dispatch_seq 单调, pull_state |
|
||||
| 54 | `apt_tablet_call_result` (T-03) | id | (gyid,result_id) | (gyid,task_id),(gyid,applied_state,occurred_at) | result_id 幂等, face_verify_state |
|
||||
| 55 | `apt_person_face_reg` (T-04) | id | (gyid,reg_id) | (gyid,reg_state,occurred_at),(gyid,work_no) | 双路状态链 upload_state / dispatch_state 独立, 媒体只存引用 |
|
||||
| 56 | `apt_transfer_order` (T-05) | id | (gyid,transfer_id) | (gyid,jcid) | new_call_time vs recomputed_call_time 不等时告警 |
|
||||
| 57 | `apt_clean_staff` (T-06) | id | (gyid,staff_id) | — | phone_ref |
|
||||
| 58 | `apt_clean_record` (T-07) | id | (gyid,record_id) | (gyid,room_id,started_at) | clean_type |
|
||||
| 59 | `apt_device_alarm` (T-08) | id | (gyid,alarm_id),(gyid,alarm_event_key) | (gyid,alarm_type,occurred_at) | alarm_event_key 去重 |
|
||||
|
||||
表 14-12 关键表示例:`apt_ops_probe`(探针专用,不计入 59 张)
|
||||
|
||||
| 列名 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `id` | `BIGINT` | PK, AUTO_INCREMENT | 代理主键 |
|
||||
| `gyid` | `VARCHAR(32)` | NOT NULL, UK 首列 | 公寓隔离标识 |
|
||||
| `probe_key` | `VARCHAR(64)` | NOT NULL, UK 次列 | 探针幂等键 |
|
||||
| `payload` | `VARCHAR(256)` | NULL | 读回比对值 |
|
||||
| `created_at` | `DATETIME(3)` | NOT NULL DEFAULT CURRENT_TIMESTAMP(3) | 写入时刻 |
|
||||
| `uk_probe_gyid_key` | — | UNIQUE (gyid, probe_key) | 重复写触发 1062 |
|
||||
| `idx_probe_gyid_time` | — | INDEX (gyid, created_at) | 按公寓查残留 |
|
||||
|
||||
> **完整逐列定义**(含每列类型、默认值、注释、`CHECK` 表达式、`UNIQUE`/`INDEX` 定义)以 `dev/sql/apt_rev01/01`~`06` 六个脚本为唯一落点;本文件表 14-6~14-11 给出全覆盖的结构索引,避免正文重复约 900 列定义。
|
||||
|
||||
### 3.3 DDL 脚本、执行顺序与幂等验证
|
||||
|
||||
表 14-13 脚本清单(严格按 CR-02 表 3-33 迁移顺序)
|
||||
|
||||
| 顺序 | 文件 | 内容 | 表数 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | `00_common.sql` | 幂等补列存储过程 `apt_add_column_if_missing` + 探针表 | 1(探针) |
|
||||
| 2 | `01_domain_01_master.sql` | 域 1 主数据 / 计划 / 本地建单 | 11 |
|
||||
| 3 | `02_domain_02_exec_device.sql` | 域 2 执行 / 设备 | 11 |
|
||||
| 4 | `03_domain_03_voice.sql` | 域 3 语音 + T-17 | 12 |
|
||||
| 5 | `04_domain_04_ledger.sql` | 域 4 账务 + T-11(只建结构) | 6 |
|
||||
| 6 | `05_domain_05_report_duty_ops.sql` | 域 5 上报 / 值班 / 运维 + T-09/10/12/13 | 11 |
|
||||
| 7 | `06_domain_06_cr02_extra.sql` | 域 6 T-01~T-08 | 8 |
|
||||
| 8 | `07_patch_columns.sql` | 幂等增量补列(空库为 no-op) | — |
|
||||
| 9 | `08_seed_replayable.sql` | 可重放种子:6 域 LOCAL 基线 + 水位 + 12 自检项 | — |
|
||||
| 10 | `99_verify.sql` | 59 张表口径 / PK / gyid / 外键 / 种子校验 | — |
|
||||
|
||||
另需先导入 `dev/RuoYi-Vue-master/sql/ry_20260417.sql` + `quartz.sql`(31 张 `sys_`/`gen_`/`QRTZ_` 框架表),否则 `sys_config` 不可读、应用无法启动。最终库内 **91 张 = 59 业务 + 31 框架 + 1 探针**。
|
||||
|
||||
---
|
||||
|
||||
## 4. 接口设计
|
||||
|
||||
### 4.1 前缀与鉴权
|
||||
|
||||
| 项 | 约定 |
|
||||
| --- | --- |
|
||||
| 前缀 | `/apt/ops/connectivity`(四前缀中的 `/apt/**`;本轮未开 `/duty/**`、`/open/v1/**`、`/platform/**`) |
|
||||
| 鉴权 | `@Anonymous` 免登录,但由 `assertAllowed` 双重限制:`apt.probe.enabled=true` 且 `remoteAddr` 为回环地址 |
|
||||
| 越权 | 非回环 `40301 NON_LOOPBACK_FORBIDDEN`;接口关闭 `40301 PROBE_DISABLED`;gyid 未注入 `40302 GY_ID_MISSING` |
|
||||
| 分页 | 本轮接口不分页;`apt.page.max-size=100` 为后续列表接口上限 |
|
||||
| 编码 | 响应 body 为 UTF-8;`server.servlet.encoding.force-response=true` 且接口 `produces` 声明 `application/json;charset=UTF-8` |
|
||||
|
||||
> **编码实测说明**:服务端 HTTP body 为合法 UTF-8(用 `json.loads(resp.read().decode('utf-8'))` 复核,中文「仅支持」正确还原);Spring MVC 的 Jackson converter 会把 `Content-Type` 写成 `application/json`(不带 `charset`)。浏览器 / curl / axios 等按 UTF-8 解码正常;Windows PowerShell 5.1 的 `Invoke-RestMethod` 按 Latin-1 解码会显示中文乱码,属客户端限制,不影响 `code` / `reason` / `traceId` 等 ASCII 字段和错误处理链路。
|
||||
|
||||
### 4.2 `GET /apt/ops/connectivity` — 只读连通性检查
|
||||
|
||||
表 14-14 请求参数
|
||||
|
||||
| 参数 | 位置 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 无 | — | — | — | 不接受任何业务参数;gyid 来自部署环境 |
|
||||
|
||||
表 14-15 返回结构
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `code` / `msg` | int / string | 统一响应头,成功 `200 / success` |
|
||||
| `data.overall` | string | `OK` / `DEGRADED` / `FAILED` |
|
||||
| `data.gyid` | string | 当前进程公寓标识 |
|
||||
| `data.traceId` | string | 32 位无横线 UUID,与日志关联 |
|
||||
| `data.elapsedMs` | long | 各探针耗时之和 |
|
||||
| `data.results[]` | array | 每项含 `target`(DB/REDIS)、`ok`、`code`、`reason`、`message`、`elapsedMs`、`details` |
|
||||
| `data.results[].details` (DB) | object | `operation=SELECT`、`select1`、`probeRows`、`gyid` |
|
||||
| `data.results[].details` (REDIS) | object | `operation=PING`、`ping=PONG`、`database=1` |
|
||||
|
||||
### 4.3 `POST /apt/ops/connectivity/probe` — 读写闭环自检
|
||||
|
||||
表 14-16 请求参数(`application/json`)
|
||||
|
||||
| 字段 | 类型 | 必填 | 默认 | 校验 / 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `target` | string | 否 | `ALL` | 仅 `DB` / `REDIS` / `ALL`(大小写不敏感);其他值 `40001 INVALID_TARGET` |
|
||||
| `strict` | boolean | 否 | `true` | `true`:任一失败即抛 `AptException` 走统一错误码;`false`:返回结构化降级结果 |
|
||||
|
||||
表 14-17 返回结构(成功)
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| `data.results[]` (DB) | `operation=INSERT/SELECT/DELETE`、`inserted=1`、`readBack=it0-probe`、`deleted=1`、`gyid` |
|
||||
| `data.results[]` (REDIS) | `operation=SET/GET/DEL`、`key=apt:rev01:probe:<16位>`、`readBack`、`deleted=true`、`database=1`、`ttlSeconds=60` |
|
||||
| 其余字段 | 与表 14-15 相同 |
|
||||
|
||||
失败响应(`strict=true` 或参数非法):`{ "code": <错误码>, "msg": "...", "data": { "reason": "...", "traceId": "...", "path": "..." } }`,**不返回堆栈**。
|
||||
|
||||
### 4.4 错误码约定
|
||||
|
||||
表 14-18 错误码表(沿用 `公寓端/04` 表 4-4 分段)
|
||||
|
||||
| 码 | 含义 | 典型 `reason` | 触发 |
|
||||
| --- | --- | --- | --- |
|
||||
| 200 | 成功 | `OK` | 全部探针通过 |
|
||||
| 40001 | 参数错误 | `INVALID_TARGET`、`INVALID_PROBE_TABLE` | target 非法、探针表名白名单不通过 |
|
||||
| 40101 | 未登录 | — | 预留(本接口匿名) |
|
||||
| 40301 | 缺少权限点 | `PROBE_DISABLED`、`NON_LOOPBACK_FORBIDDEN` | 开关关闭 / 非回环来源 |
|
||||
| 40302 | gyid 越界或缺失 | `GY_ID_MISSING` | 上下文未注入 |
|
||||
| 40401 | 资源不存在 | — | 预留 |
|
||||
| 40901 | 业务键重复 | `DUPLICATE_KEY` | `DuplicateKeyException`(MySQL 1062) |
|
||||
| 50301 | 依赖不可用 | `DB_CONNECT_FAILED`、`DB_TIMEOUT`、`DB_ERROR`、`REDIS_CONNECT_FAILED`、`REDIS_TIMEOUT`、`REDIS_ERROR`、`DEPENDENCY_TIMEOUT`、`DEPENDENCY_ERROR` | 连接失败 / 超时 / 命令异常 |
|
||||
| 50304 | 数据异常(本轮同段新增) | `SCHEMA_MISMATCH`、`DATA_INTEGRITY_VIOLATION`、`DB_READ_MISMATCH`、`DB_READ_WRITE_MISMATCH`、`REDIS_DB_MISMATCH`、`REDIS_READ_MISMATCH`、`REDIS_READ_WRITE_MISMATCH` | 表缺失 / CHECK 违反 / 读写结果不符 / database≠1 |
|
||||
| 500 | 内部错误 | — | 兜底 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 连接、读写与异常处理策略
|
||||
|
||||
表 14-19 连接与超时配置
|
||||
|
||||
| 层 | 参数 | 值 | 作用 |
|
||||
| --- | --- | --- | --- |
|
||||
| JDBC URL | `connectTimeout` / `socketTimeout` | 5000 / 30000 ms | 建连与读超时快速失败 |
|
||||
| Druid | `maxWait` / `maxActive` / `minIdle` | 5000 ms / 20 / 2 | 池耗尽 5s 快速失败,避免线程挂起 |
|
||||
| Druid | `validationQuery=SELECT 1`、`testOnBorrow=true`、`testWhileIdle=true` | — | 借出即校验,坏连接剔除 |
|
||||
| Druid | `connection-init-sqls=SET NAMES utf8mb4` | — | 字符集一致,防中文乱码 |
|
||||
| Druid | 控制台 | 默认关闭 | 减少攻击面 |
|
||||
| `JdbcTemplate` | `setQueryTimeout` | `max(1, apt.probe.timeout-ms/1000)` 秒 | 单次查询硬超时 |
|
||||
| Redis | `timeout` / `connect-timeout` | 3s / 3s | 命令与建连超时 |
|
||||
| Lettuce | `max-active` / `max-wait` | 16 / 2s | 池耗尽快速失败 |
|
||||
| 探针 | `apt.probe.timeout-ms` | 2000 ms | 二次判定:即使底层未抛超时,`elapsedMs` 超限也归为 `*_TIMEOUT` |
|
||||
| 探针 | `redis-ttl-seconds` | 60 s | 进程异常退出时 key 自动过期 |
|
||||
| 响应 | `force-response` UTF-8 | — | 中文错误信息不乱码 |
|
||||
|
||||
表 14-20 异常场景矩阵
|
||||
|
||||
| 场景 | 底层现象 | 捕获 / 判定 | 错误码 | `reason` | 兜底与恢复 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| DB 连接失败 | MySQL 1045 / 2003 | `CannotGetJdbcConnectionException` | 50301 | `DB_CONNECT_FAILED` | 连接池剔除坏连接;fail-fast 不回退默认口令;日志带 traceId |
|
||||
| DB 超时 | 慢查询 / 网络挂起 | `QueryTimeoutException`,或 `elapsedMs > 阈值` | 50301 | `DB_TIMEOUT` / `DEPENDENCY_TIMEOUT` | `setQueryTimeout` 中断查询;`finally` 清理探针行 |
|
||||
| Redis 连接失败 | 连接拒绝 / 超时 | `RedisConnectionFailureException` | 50301 | `REDIS_CONNECT_FAILED` | 3s 超时快速失败;不阻塞 DB 探针结果 |
|
||||
| Redis 超时 | 命令超时 | `QueryTimeoutException` / `elapsedMs` | 50301 | `REDIS_TIMEOUT` | `spring.data.redis.timeout=3s` 兜底;key 带 TTL |
|
||||
| 重复键 | MySQL 1062 | `DuplicateKeyException` | 40901 | `DUPLICATE_KEY` | 幂等键不新增行;事务回滚 |
|
||||
| 完整性 / CHECK | MySQL 3819 | `DataIntegrityViolationException` | 50304 | `DATA_INTEGRITY_VIOLATION` | 事务回滚;不写半截数据 |
|
||||
| 表结构缺失 | MySQL 1146 | `BadSqlGrammarException` | 50304 | `SCHEMA_MISMATCH` | 提示先执行 `00`~`06`;恢复表后自愈 |
|
||||
| Redis database 错误 | `SELECT 99` 报 `ERR DB index is out of range` | `redisDatabase()` 与期望值 1 比对 | 50304 | `REDIS_DB_MISMATCH` | 拒绝写入,避免写错库 |
|
||||
| 读写结果不符 | `SELECT`/`GET` 回读不一致 | 显式比对 `inserted/deleted/readBack` | 50304 | `DB_READ_WRITE_MISMATCH` / `REDIS_READ_WRITE_MISMATCH` | `finally` 二次清理 |
|
||||
| 探针表名注入 | 配置被篡改 | 正则 `[A-Za-z0-9_]+` 白名单 | 40001 | `INVALID_PROBE_TABLE` | 拒绝拼接 SQL |
|
||||
| gyid 缺失 | 拦截器未生效 | `AptContext.getGyId()` | 40302 | `GY_ID_MISSING` | 不降级为全库操作 |
|
||||
| 清理失败 | 删除探针数据时依赖已断 | `finally` 内 `catch` 吞掉 | 不影响主结果 | 日志 WARN | 探针 key 有 TTL,探针表可重放清理 |
|
||||
| 未知异常 | 其他 `DataAccessException` | 兜底 handler | 50301 | `DEPENDENCY_ERROR` | 只回 `reason` + `traceId`,不外泄堆栈 |
|
||||
|
||||
**不残留脏数据**:DB 探针走 `INSERT → SELECT → DELETE`,`finally` 再执行一次幂等 `DELETE`;Redis 探针走 `SET(TTL) → GET → DEL`,`finally` 再 `DEL`。实测 `probeRows=0`、key 被清除。
|
||||
|
||||
---
|
||||
|
||||
## 6. 验证结果
|
||||
|
||||
表 14-21 本轮实际执行的验证(全部通过)
|
||||
|
||||
| # | 验证项 | 手段 | 结果 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | MySQL 连接(用户提供凭据) | `mysql.exe` | 成功,MySQL 9.5.0,库 `apt_rev01` |
|
||||
| 2 | Redis `database=1` 连通与读写 | RESP 原生 PING/SELECT/SET/GET/DEL | `+PONG` / `+OK` / `ok` / `:1` |
|
||||
| 3 | DDL 首次执行 | `00`~`08` 按序 | 9 个脚本 `EXIT=0` |
|
||||
| 4 | 59 张表口径 | `99_verify.sql` | `business_table_count=59`;分布 apt 36 / gy 17 / gygl 1 / duty 5 |
|
||||
| 5 | 主键 / gyid / 外键 | `99_verify.sql` | 缺 PK 0 行、缺 gyid 0 行、外键 0 个 |
|
||||
| 6 | 二次执行幂等 | 全套脚本重跑后再校验 | 表数仍 59,种子仍 6 / 12,无重复 |
|
||||
| 7 | 框架表 | `ry_20260417.sql` + `quartz.sql` | 91 张,`sys_config` 可读 |
|
||||
| 8 | DB 读写闭环 | SQL INSERT/SELECT/DELETE | 写入、回读、删除各 1 行,残留 0 |
|
||||
| 9 | 重复键异常 | 双 INSERT 同 UK | `ERROR 1062` → 映射 `40901` |
|
||||
| 10 | CHECK 约束异常 | 插入非法 `state` | `ERROR 3819` → 映射 `50304` |
|
||||
| 11 | 连接失败 / 拒绝 | 错误口令、错误端口 | `1045` / `2003` → 映射 `50301` |
|
||||
| 12 | Redis 异常分支 | `SELECT 99`、未知命令、错误端口 | `ERR DB index is out of range` / `ERR unknown command` / 连接超时 |
|
||||
| 13 | Maven 编译 | JDK 24 + Maven 3.8.1 | 7 模块 `BUILD SUCCESS` |
|
||||
| 14 | 单测 | Surefire 3.5.2 + JUnit5 | `Tests run: 12, Failures: 0, Errors: 0` |
|
||||
| 15 | 打包 | `spring-boot-maven-plugin` | `ruoyi-admin.jar`(90 MB) |
|
||||
| 16 | 端到端 GET | 启动 jar + HTTP | `overall=OK`,DB select1=1,Redis PING=PONG,database=1 |
|
||||
| 17 | 端到端 POST | `target=ALL, strict=false` | DB `1/it0-probe/1`、Redis `SET/GET/DEL` 全部 `OK` |
|
||||
| 18 | 端到端参数异常 | `target=UNKNOWN` | `40001 INVALID_TARGET`,带 traceId |
|
||||
| 19 | 端到端数据异常 | `DROP TABLE apt_ops_probe` | `50304 SCHEMA_MISMATCH`,`overall=FAILED` |
|
||||
| 20 | 恢复自愈 | 重建表后复验 | `overall=OK`,读写闭环恢复 |
|
||||
|
||||
> 说明:第 16~20 项为**真实启动 Spring Boot 应用**后的 HTTP 实测,凭据通过进程环境变量注入,未写入任何仓库文件。
|
||||
|
||||
---
|
||||
|
||||
## 7. 与开发计划对应及后续衔接
|
||||
|
||||
表 14-22 `IT-0` 验收对照(`13` 表 13-10)
|
||||
|
||||
| `13` 验收项 | 本轮落地 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| ① 基线决策与契约冻结签字 | 6 项 P0 前提已在表 14-2 登记,代码按冻结前口径实现 | **部分达成**:技术基线 / Q-20 / Q-40 / Q-43 / Q-48 仍需冻结会签字 |
|
||||
| ② 仓库无明文口令 + CI 扫描 | 凭据外置 `.env`(已忽略)、CI 双规则扫描 | 达成 |
|
||||
| ③ DDL 与回填分离、二次执行幂等 | 表 14-13 + 验证 #6 | 达成 |
|
||||
| ④ `sys_config` 可读、应用以 local 启动无异常 | 验证 #7 / #16 | 达成 |
|
||||
| ⑤ 无业务 Controller | 仅自检接口 | 达成 |
|
||||
|
||||
表 14-23 后续迭代衔接
|
||||
|
||||
| 迭代 | 本轮提供的前置 | 下一轮要做 |
|
||||
| --- | --- | --- |
|
||||
| `IT-1` M0 运行时基座 | 错误码 / gyid 上下文 / 四前缀中 `/apt/**` 拦截器骨架 / 测试与 CI | 补齐 `/duty/**`、`/open/v1/**` 拦截器与权限点种子、`sys_menu` 权限点、审计切面 |
|
||||
| `IT-2`~`IT-3` | 59 张表结构、幂等补列脚本 | 主数据 / 房间 / 人脸最小闭环业务代码(落 `ruoyi-system`) |
|
||||
| `IT-4`~`IT-5` | `apt_local_task` / `gy_jcxx` 结构、单一状态写入口约束 | 入住 CI-01~CI-05、叫乘状态机 M3 |
|
||||
| `IT-9`~`IT-11` 延后域 | 账务 6 张表**已建结构但不开放读写**、错误码与权限点可预埋 | 阶段三退出 + `D1/D2/P-07/Q-41~Q-45` 决策后再开 `/apt/ledger/**` |
|
||||
|
||||
---
|
||||
|
||||
## 8. 变更点与影响范围
|
||||
|
||||
| 类别 | 变更 | 影响范围 |
|
||||
| --- | --- | --- |
|
||||
| 新增 | `dev/sql/apt_rev01/*.sql`(10 个脚本) | 数据库 `apt_rev01`:59 业务表 + 1 探针表 |
|
||||
| 新增 | `com.ruoyi.apt.**` 共 9 个 Java 类(common 3 / framework 5 / admin 1) | 后端编译与运行时;不改任何既有 `com.ruoyi.*` 类 |
|
||||
| 新增 | 3 个测试类 + `maven-surefire-plugin` 3.5.2 + `spring-boot-starter-test` | `ruoyi-admin` 构建;修正了原 `surefire 2.12.4` 静默漏跑 JUnit5 用例的问题 |
|
||||
| 修改 | `application-druid.yml`、`application.yml` | 数据源指向 `apt_rev01`、Redis `database=1`、springdoc 扫 `com.ruoyi.apt.**`、凭据全部外置 |
|
||||
| 新增 | `.gitignore`、`dev/.env.example`、`dev/scripts/run-local.ps1`、`.github/workflows/it0-verify.yml` | 仓库级;不改动既有文件 |
|
||||
| 新增 | 本文档 `公寓端/14` | 文档索引 |
|
||||
| **不变** | CR-02 §12~§15 权威表述、跨端 20 编号、`v2-draft`、公寓本地库 59 张表、平台零回调、统计结果不回写、`F-A`~`F-Q`、Q-01~Q-50 | 无任何设计口径改动;未新增 `M7` / 阶段六 / `D-4` / `Q-*` / `R-*` / 施工单编号 |
|
||||
| **待办** | 表 14-2 的 6 项口径偏离须评审签字;`IR-01` 技术基线冲突须冻结会定稿 | `IT-1` 开工前 |
|
||||
@@ -32,6 +32,7 @@
|
||||
| `11-人员入住作业流程.md` | **人员入住作业流程**:注册与签到、入住申请(房间 / 交路)、值班员审核与房间调整、#9 提报与平台运安匹配、#7 任务查询进入叫乘;三条状态链、`apt_local_task` 补列、N-38~N-47 请求 / 响应字段、Q-36~Q-40、表 11-1~11-35 | CR-02 §13(CR-C26~CR-C30、F-K、验收 18~20) |
|
||||
| `12-消费充值与菜品管理.md` | **消费、充值与菜品管理**:人员消费(选餐加菜显示金额 → 查双额度 → 补贴优先 / 现金补足 → 上报并同步平台账户)、人员线下充值(扫码识别 → 管理员核对 → 计入现金额度 → 同步平台)、公寓菜品管理(阶段性食谱发布 → 终端查看并加入选择菜单 → 远程点菜预留);四条状态链、`gy_ykt_*` / `YKT_MEALS` 补列、N-48~N-58 请求 / 响应字段、Q-41~Q-45、表 12-1~12-34 | CR-02 §14(CR-C31~CR-C35、F-L / F-M / F-N、验收 21~23) |
|
||||
| `13-公寓端小步迭代开发计划.md` | **实施排期设计稿(非设计变更)**:`dev/` 实测上游、`IT-0`~`IT-8` 迭代目标 / 范围 / 依赖 / 验收、里程碑 `MS-0`~`MS-5`、交付物 `DV-0`~`DV-8`、设计文档 × 代码模块对齐矩阵、6 项 P0 排期前提与 `IR-01`~`IR-14` 风险台账、跨迭代联调与回归基线、`IT-9`~`IT-11` 消费 / 充值 / 菜品衔接;表 13-1~13-32、图 13-1 | 开发排期与联调(**阶段 / 验收口径仍以 `07` 为准**) |
|
||||
| `14-第一轮开发(IT-0)交付说明.md` | **第一轮实现交付说明**:模块职责边界与依赖图、59 张表全量字段 / 主键 / 唯一键 / 索引设计、DDL 脚本与迁移顺序、自检接口的请求参数 / 返回结构 / 错误码约定、连接失败 / 超时 / 数据异常处理矩阵、20 项实测验证结果、口径偏离与后续衔接;表 14-1~14-23、图 14-1 | `IT-0` 落地与验收(代码在 `dev/RuoYi-Vue-master`、`dev/sql/apt_rev01`) |
|
||||
| `../设计变更/03-三端功能设计修订(CR-02).md` | **权威增量**:三端覆盖范围、交互协议、交互数据、模块与数据表、关键流程变更、施工单 | CR-02 |
|
||||
|
||||
## 1. 编号与引用约定
|
||||
@@ -104,6 +105,7 @@ flowchart LR
|
||||
K --> L["11 人员入住作业流程"]
|
||||
L --> M["12 消费、充值与菜品管理"]
|
||||
M --> N["13 小步迭代开发计划(排期 / 联调)"]
|
||||
N --> O["14 第一轮开发 IT-0 交付说明(实现 / 验收)"]
|
||||
```
|
||||
|
||||
图 0-1 阅读路径
|
||||
|
||||
Reference in new issue
Block a user