chenxing b3478afddd t17:oapi v2 增量拉取 + RabbitMQ 事件(可选依赖、信封十字段闭集、软删防回归断言)
- GET /oapi/form/answers(契约 §6.1/C9/C11/C12):域校验走 readDomainForm(他校与不存在同一条
  "表单不存在",V54;软删表单照读,§5.4/P32),行集恒带 sch_id。增量口径按冻结状态二分且不接受混用
  (混用给可诊断拒绝,而不是静默返回一个"看起来正常"的空窗口):
  冻结=append-only + after=answer_uuid(服务端按 uk 换算库内 id,id 绝不出响应,V53,墓碑照常下发);
  非冻结=updated_since + 复合键 (update_time, answer_uuid),续拉游标 {ISO8601}|{answer_uuid}(P126)。
  limit 1~2000 越界拒不夹;nextCursor 只在这一页填满时给(宁可末尾多要一次空页,不可少要一次)。
- 行字段是 §6.1 的 15 键闭集(逐字段 @JsonProperty,外层 rows/nextCursor 按 C9 原文 camelCase——
  命名差异是契约原文,不加"顺手统一"的适配层);meta.ip/ua 只匿名行有值(C12),登录行两项 null。
- 时间线格式降到整秒并对齐列精度(DATETIME 秒粒度;带纳秒的游标与列值比不出等值,
  同事务重读还会经一级缓存拿到内存对象):取舍方向是"宁可重复投递也不漏行",
  重复投递正是 C9 明写的 at-least-once(P127)。IT 侧 flush+clear 把读取摆回生产形态。
- 新 FcEventPublisher(§6.2/V62/V63/V64):RABBITMQ_HOST 未注入=整体 no-op + 启动一条说明日志;
  RabbitTemplate 走 ObjectProvider(可选依赖不该在缺 bean 时拖垮上下文);exchange fc.events.v1
  惰性 durable topic 声明(声明失败放回标志位允许重试);routing key fc.answer.{app_code}.{action};
  afterCommit 发布且信封在注册前按实体快照组好;发布失败只 warn 不抛(没有 outbox、没有死信)。
  信封十字段闭集、不含值文档(裁决 1:MQ 是通知通道不是数据通道)。
- 发布点三处:submit 写库段后=created(代录/导入同管线自动获得);两处编辑写库段=updated
  (能走到即说明未开冻结,V61 已在前面拦);两处软删实体 save 后=tombstoned(公共出口是发布器那一个方法)。
- 依赖与配套:pom 加 spring-boot-starter-amqp(BOM 管版本);yml 的 spring.rabbitmq.* 全从
  RABBITMQ_* env 现读,并关 rabbit 健康探针与 Boot 的 RabbitAdmin(dynamic=false)——
  后者启动就拨号声明拓扑,无 broker 环境实测把上下文启动拖到分钟级,拓扑已由发布器自己声明。

测试:OapiAnswersIT 8 例(闭集无 id、口径二分互不混用、limit 边界、after 翻页+重放+墓碑可见、
V70 软删前移 update_time 才让墓碑进窗口、复合游标带 uuid 尾、他校同文面、匿名行 meta)
+ FcEventPublisherTest 5 例(V63 十字段闭集、routing key、未配置即 no-op、afterCommit 之前不发、
异常被吞)+ MqDisabledContextIT 2 例(无 broker:enabled()=false 与 /actuator/health 仍 UP)。
门禁:定向 15 例全绿(s6-gate-2.log),本段另跑过一次全量 288 例全绿(mvn-full-2.log,
按协调口径后续段不再连发全量,全量留 S8 收口)。差额 P126/P127/P128。
2026-10-20 17:17:40 +08:00
2026-10-14 11:41:44 +08:00
2026-10-14 11:41:39 +08:00

form-center-service

managed by projman

S
Description
managed by projman
Readme
1.2 MiB
Languages
Java 99.9%