docs: anchor booking agent session implementation
This commit is contained in:
parent
4815387c23
commit
3c1f89a2d6
@ -3,7 +3,7 @@
|
|||||||
> 本体条目 ↔ 文档章节 ↔ 代码路径 ↔ 测试用例 三方对齐审计。
|
> 本体条目 ↔ 文档章节 ↔ 代码路径 ↔ 测试用例 三方对齐审计。
|
||||||
> 证据强度:`anchored`(三处对齐)/ `documented`(仅文档)/ `implemented`(仅代码)/ `gap`(缺失)。
|
> 证据强度:`anchored`(三处对齐)/ `documented`(仅文档)/ `implemented`(仅代码)/ `gap`(缺失)。
|
||||||
>
|
>
|
||||||
> **刷新时间**:2026-08-02(智能预约 M0 Batch 0 契约冻结后刷新)
|
> **刷新时间**:2026-08-02(智能预约 M0 Batch 2 会话与只读编排实现后刷新)
|
||||||
|
|
||||||
## 审计方法
|
## 审计方法
|
||||||
|
|
||||||
@ -25,9 +25,9 @@
|
|||||||
| Relation | 112 |
|
| Relation | 112 |
|
||||||
| **合计** | **313** |
|
| **合计** | **313** |
|
||||||
|
|
||||||
证据强度:`anchored` 250(79.9%)/ `documented` 52 / `gap` 9 / `implemented` 2。
|
证据强度:`anchored` 274(87.5%)/ `documented` 28 / `gap` 9 / `implemented` 2。
|
||||||
|
|
||||||
> anchored 占比相对早期快照下降,是因为主动录入了 P1/P2 `gap`、客户端埋点和智能预约 Batch 0 `documented` 条目;端点漂移仍为 0。
|
> 智能预约 Batch 2 的真实代码与测试已替换 24 条计划证据;P1/P2 `gap` 和未实现客户端埋点仍保留原证据强度,端点与 JPA 实体漂移均为 0。
|
||||||
|
|
||||||
校验:
|
校验:
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ python3 docs/graph/validate_ontology.py docs
|
|||||||
python3 docs/graph/audit_drift.py
|
python3 docs/graph/audit_drift.py
|
||||||
```
|
```
|
||||||
|
|
||||||
当前结果:校验通过;HTTP 端点 68/68、JPA Entity 16/16 对齐;非 JPA/计划领域实体 14 个;代码与本体均无单边漂移。智能预约五个未实现端点以 `planned METHOD /path` 建模,不冒充当前代码端点。
|
当前结果:校验通过;HTTP 端点 73/73、JPA Entity 17/17 对齐;非 JPA/计划领域实体 13 个;代码与本体均无单边漂移。智能预约五个端点及会话实体已由 Batch 2 真实代码和测试锚定。
|
||||||
|
|
||||||
## 元数据卫生
|
## 元数据卫生
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ python3 docs/graph/audit_drift.py
|
|||||||
| customer_timeline | ✅ | ✅ read model | StoreCustomerTimelineServiceTest | anchored | StoreCustomer + BusinessEvent 的同店低敏事实投影;jpa:false |
|
| customer_timeline | ✅ | ✅ read model | StoreCustomerTimelineServiceTest | anchored | StoreCustomer + BusinessEvent 的同店低敏事实投影;jpa:false |
|
||||||
| highlight_fail_reason | ✅ | ✅ 枚举 | ReportHighlightVideoServiceTest | anchored | jpa:false |
|
| highlight_fail_reason | ✅ | ✅ 枚举 | ReportHighlightVideoServiceTest | anchored | jpa:false |
|
||||||
| current_user | ✅ | ✅ record | SessionTokenServiceTest | anchored | jpa:false |
|
| current_user | ✅ | ✅ record | SessionTokenServiceTest | anchored | jpa:false |
|
||||||
| booking_agent_session | ✅ | —(Batch 0 设计) | — | documented | M0 短期会话;实现批创建 JPA/迁移/测试后才可改 anchored |
|
| booking_agent_session | ✅ | ✅ | BookingAgentSessionMigrationTest / BookingAgentServiceTest | anchored | M0 短期会话;六态、owner/store、版本与 TTL,不关联 Appointment |
|
||||||
| membership 等 5 个 | 方向库 | — | — | gap | roadmap 占位 |
|
| membership 等 5 个 | 方向库 | — | — | gap | roadmap 占位 |
|
||||||
|
|
||||||
## 规则覆盖度(55 条)
|
## 规则覆盖度(55 条)
|
||||||
@ -149,14 +149,14 @@ python3 docs/graph/audit_drift.py
|
|||||||
|
|
||||||
当前 validate 规模以脚本输出为准(313 条目)。
|
当前 validate 规模以脚本输出为准(313 条目)。
|
||||||
|
|
||||||
## 智能预约 M0 Batch 0 状态(2026-08-02)
|
## 智能预约 M0 Batch 2 状态(2026-08-02)
|
||||||
|
|
||||||
| 类型 | 已冻结 ID | 证据 |
|
| 类型 | 已冻结 ID | 证据 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| Entity | `entity:booking_agent_session` | documented |
|
| Entity | `entity:booking_agent_session` | anchored |
|
||||||
| Action | `create/submit/transcribe/handoff/cancel_booking_agent_*` 共 5 条 | documented |
|
| Action | `create/submit/transcribe/handoff/cancel_booking_agent_*` 共 5 条 | anchored |
|
||||||
| Event | `booking_agent_started/draft_ready/fallback` | documented |
|
| Event | `booking_agent_started/draft_ready/fallback` | anchored |
|
||||||
| Rule | `BR-BA-001..005` | documented |
|
| Rule | `BR-BA-001..005` | anchored |
|
||||||
| Relation | owner/store/session 读写与三条 EMITS 共 10 条 | documented |
|
| Relation | owner/store/session 读写与三条 EMITS 共 10 条 | anchored |
|
||||||
|
|
||||||
契约评审已通过,尚未实现。下一实现批必须以真实 code/test 路径替换空证据,并将 `BookingAgentSession` 从计划对象切换为真实 JPA 实体;禁止仅修改 `evidence` 文字。
|
Batch 2 已以真实 code/test 路径锚定会话、权限、状态/版本/TTL、音频边界、只读号源与低敏事件。Batch 3 前端仍未实现;真实供应商 smoke 与生产开启仍未授权。
|
||||||
|
|||||||
@ -2,13 +2,13 @@
|
|||||||
"""
|
"""
|
||||||
宠小它 本体—代码漂移审计脚本。
|
宠小它 本体—代码漂移审计脚本。
|
||||||
|
|
||||||
扫描 backend/src/main/java/com/petstore/controller/*.java,提取所有 HTTP 端点
|
递归扫描 backend/src/main/java/com/petstore 下的 *Controller.java,提取所有 HTTP 端点
|
||||||
(类级 @RequestMapping + 方法级 @GetMapping/@PostMapping/@PutMapping/@DeleteMapping),
|
(类级 @RequestMapping + 方法级 @GetMapping/@PostMapping/@PutMapping/@DeleteMapping),
|
||||||
对比 docs/graph/ontology.jsonl 中 Action 的 entrypoints,报告:
|
对比 docs/graph/ontology.jsonl 中 Action 的 entrypoints,报告:
|
||||||
|
|
||||||
1. code-only:代码里有但本体未录入的端点(drift:应补录本体或确认废弃)
|
1. code-only:代码里有但本体未录入的端点(drift:应补录本体或确认废弃)
|
||||||
2. ontology-only:本体里有但代码里找不到的端点(drift:可能是已删除接口或路径写错)
|
2. ontology-only:本体里有但代码里找不到的端点(drift:可能是已删除接口或路径写错)
|
||||||
3. entity-coverage:扫描 backend/src/main/java/com/petstore/entity/*.java,对比 ontology.jsonl 的 Entity,
|
3. entity-coverage:递归扫描 backend/src/main/java/com/petstore 下的 @Entity 类,对比 ontology.jsonl 的 Entity,
|
||||||
报告未录入的实体类。
|
报告未录入的实体类。
|
||||||
|
|
||||||
用法:
|
用法:
|
||||||
@ -28,21 +28,31 @@ VALID_TYPES = {"Entity", "Action"}
|
|||||||
|
|
||||||
|
|
||||||
def find_controller_files(repo_root):
|
def find_controller_files(repo_root):
|
||||||
ctrl_dir = os.path.join(repo_root, "backend", "src", "main", "java", "com", "petstore", "controller")
|
source_root = os.path.join(repo_root, "backend", "src", "main", "java", "com", "petstore")
|
||||||
if not os.path.isdir(ctrl_dir):
|
if not os.path.isdir(source_root):
|
||||||
return []
|
return []
|
||||||
return sorted(
|
files = []
|
||||||
os.path.join(ctrl_dir, f) for f in os.listdir(ctrl_dir) if f.endswith(".java")
|
for directory, _, names in os.walk(source_root):
|
||||||
|
files.extend(
|
||||||
|
os.path.join(directory, name)
|
||||||
|
for name in names
|
||||||
|
if name.endswith("Controller.java")
|
||||||
)
|
)
|
||||||
|
return sorted(files)
|
||||||
|
|
||||||
|
|
||||||
def find_entity_files(repo_root):
|
def find_entity_files(repo_root):
|
||||||
ent_dir = os.path.join(repo_root, "backend", "src", "main", "java", "com", "petstore", "entity")
|
source_root = os.path.join(repo_root, "backend", "src", "main", "java", "com", "petstore")
|
||||||
if not os.path.isdir(ent_dir):
|
if not os.path.isdir(source_root):
|
||||||
return []
|
return []
|
||||||
return sorted(
|
files = []
|
||||||
os.path.join(ent_dir, f) for f in os.listdir(ent_dir) if f.endswith(".java")
|
for directory, _, names in os.walk(source_root):
|
||||||
|
files.extend(
|
||||||
|
os.path.join(directory, name)
|
||||||
|
for name in names
|
||||||
|
if name.endswith(".java")
|
||||||
)
|
)
|
||||||
|
return sorted(files)
|
||||||
|
|
||||||
|
|
||||||
# 类级 @RequestMapping("/api/xxx")
|
# 类级 @RequestMapping("/api/xxx")
|
||||||
|
|||||||
@ -140,7 +140,7 @@
|
|||||||
{"id":"rule:BR-USER-002","type":"Rule","name":"用户更新仅本人","domain":"user","appliesTo":["action:update_user","action:get_user_info"],"code":"backend/src/main/java/com/petstore/controller/UserController.java#updateUser; #info","evidence":"anchored"}
|
{"id":"rule:BR-USER-002","type":"Rule","name":"用户更新仅本人","domain":"user","appliesTo":["action:update_user","action:get_user_info"],"code":"backend/src/main/java/com/petstore/controller/UserController.java#updateUser; #info","evidence":"anchored"}
|
||||||
{"id":"rule:BR-CONFIG-001","type":"Rule","name":"生产配置环境变量","domain":"config","appliesTo":[],"code":"backend/src/main/resources/application.yml; application-example.yml","doc":"backend/README.md 环境变量表","evidence":"anchored"}
|
{"id":"rule:BR-CONFIG-001","type":"Rule","name":"生产配置环境变量","domain":"config","appliesTo":[],"code":"backend/src/main/resources/application.yml; application-example.yml","doc":"backend/README.md 环境变量表","evidence":"anchored"}
|
||||||
{"id":"rule:BR-CONFIG-002","type":"Rule","name":"production profile 强制只读 schema 安全配置","domain":"config","appliesTo":[],"code":"backend/src/main/resources/application.yml production profile; backend/src/main/java/com/petstore/config/ProductionConfigurationValidator.java; backend/src/main/java/com/petstore/config/CorsConfig.java; backend/src/main/java/com/petstore/PetstoreApplication.java","doc":"backend/README.md production profile; docs/架构决策-全局CORS单一策略-2026-08-02.md; docs/架构决策-SessionToken严格过期边界-2026-08-02.md","test":"ProductionConfigurationValidatorTest; CorsBoundaryContractTest","evidence":"anchored","note":"生产禁用自动建表/show-sql/SMS 万能码/默认数据初始化,并拒绝弱密钥、越界 session TTL、占位域名和宽 CORS;全局 CorsFilter 是唯一策略,Controller 禁止局部 @CrossOrigin"}
|
{"id":"rule:BR-CONFIG-002","type":"Rule","name":"production profile 强制只读 schema 安全配置","domain":"config","appliesTo":[],"code":"backend/src/main/resources/application.yml production profile; backend/src/main/java/com/petstore/config/ProductionConfigurationValidator.java; backend/src/main/java/com/petstore/config/CorsConfig.java; backend/src/main/java/com/petstore/PetstoreApplication.java","doc":"backend/README.md production profile; docs/架构决策-全局CORS单一策略-2026-08-02.md; docs/架构决策-SessionToken严格过期边界-2026-08-02.md","test":"ProductionConfigurationValidatorTest; CorsBoundaryContractTest","evidence":"anchored","note":"生产禁用自动建表/show-sql/SMS 万能码/默认数据初始化,并拒绝弱密钥、越界 session TTL、占位域名和宽 CORS;全局 CorsFilter 是唯一策略,Controller 禁止局部 @CrossOrigin"}
|
||||||
{"id":"rule:BR-CONFIG-003","type":"Rule","name":"生产发布只读门禁","domain":"config","appliesTo":[],"code":"backend/src/main/java/com/petstore/config/ProductionDatabasePreflightRunner.java; backend/src/main/java/com/petstore/config/PetstoreRuntimeHealthIndicator.java; backend/deploy/release-preflight.sh; backend/deploy/production-smoke.sh","doc":"docs/生产发布与回滚Runbook-2026-08-01.md; docs/生产监控与告警基线-2026-08-01.md","test":"CorsBoundaryContractTest","evidence":"anchored","note":"备份和八迁移后运行 schema validate + 31 项只读不变量;readiness 覆盖 DB/磁盘/上传/FFmpeg;自动 smoke 只读并验证 CORS allow/deny"}
|
{"id":"rule:BR-CONFIG-003","type":"Rule","name":"生产发布只读门禁","domain":"config","appliesTo":[],"code":"backend/src/main/java/com/petstore/config/ProductionDatabasePreflightRunner.java; backend/src/main/java/com/petstore/config/PetstoreRuntimeHealthIndicator.java; backend/deploy/release-preflight.sh; backend/deploy/production-smoke.sh","doc":"docs/生产发布与回滚Runbook-2026-08-01.md; docs/生产监控与告警基线-2026-08-01.md","test":"CorsBoundaryContractTest","evidence":"anchored","note":"备份并执行目标版本全部迁移后运行 schema validate + 31 项只读不变量;readiness 覆盖 DB/磁盘/上传/FFmpeg;自动 smoke 只读并验证 CORS allow/deny"}
|
||||||
{"id":"rel:user_owns_pets","type":"Relation","subject":"entity:user","predicate":"OWNS","object":"entity:pet","cardinality":"1—N","evidence":"anchored","doc":"Pet.owner_user_id → User.id","domain":"user"}
|
{"id":"rel:user_owns_pets","type":"Relation","subject":"entity:user","predicate":"OWNS","object":"entity:pet","cardinality":"1—N","evidence":"anchored","doc":"Pet.owner_user_id → User.id","domain":"user"}
|
||||||
{"id":"rel:pet_has_appointments","type":"Relation","subject":"entity:pet","predicate":"HAS","object":"entity:appointment","cardinality":"1—N","evidence":"anchored","doc":"Appointment.pet_id(可空)","domain":"pet"}
|
{"id":"rel:pet_has_appointments","type":"Relation","subject":"entity:pet","predicate":"HAS","object":"entity:appointment","cardinality":"1—N","evidence":"anchored","doc":"Appointment.pet_id(可空)","domain":"pet"}
|
||||||
{"id":"rel:store_has_service_types","type":"Relation","subject":"entity:store","predicate":"HAS","object":"entity:service_type","cardinality":"1—N","evidence":"anchored","doc":"ServiceType.store_id(NULL=系统默认)","domain":"store"}
|
{"id":"rel:store_has_service_types","type":"Relation","subject":"entity:store","predicate":"HAS","object":"entity:service_type","cardinality":"1—N","evidence":"anchored","doc":"ServiceType.store_id(NULL=系统默认)","domain":"store"}
|
||||||
@ -287,27 +287,27 @@
|
|||||||
{"id":"rel:create_appointment_emits_rebook_created","type":"Relation","subject":"action:create_appointment","predicate":"EMITS","object":"event:rebook_created","domain":"lead","evidence":"anchored"}
|
{"id":"rel:create_appointment_emits_rebook_created","type":"Relation","subject":"action:create_appointment","predicate":"EMITS","object":"event:rebook_created","domain":"lead","evidence":"anchored"}
|
||||||
{"id":"rel:br_fu_001_applies_follow_up","type":"Relation","subject":"rule:BR-FU-001","predicate":"APPLIES_TO","object":"action:start_follow_up_task","domain":"lead","evidence":"anchored"}
|
{"id":"rel:br_fu_001_applies_follow_up","type":"Relation","subject":"rule:BR-FU-001","predicate":"APPLIES_TO","object":"action:start_follow_up_task","domain":"lead","evidence":"anchored"}
|
||||||
{"id":"rel:br_fu_002_applies_create_appointment","type":"Relation","subject":"rule:BR-FU-002","predicate":"APPLIES_TO","object":"action:create_appointment","domain":"lead","evidence":"anchored"}
|
{"id":"rel:br_fu_002_applies_create_appointment","type":"Relation","subject":"rule:BR-FU-002","predicate":"APPLIES_TO","object":"action:create_appointment","domain":"lead","evidence":"anchored"}
|
||||||
{"id":"entity:booking_agent_session","type":"Entity","name":"BookingAgentSession","nameZh":"智能预约短期会话","domain":"booking_agent","jpa":false,"fields":["id","session_id","customer_user_id","store_id","status","draft_json","draft_version","entry_source","input_modality","expires_at","create_time","update_time"],"systems":["Backend Core","Customer Experience FE"],"code":"","doc":"docs/ontology/objects.md#entity:booking_agent_session; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned","note":"Batch 0 冻结设计;尚未创建 JPA 实体,实现批需将 jpa 与证据切换为真实状态"}
|
{"id":"entity:booking_agent_session","type":"Entity","name":"BookingAgentSession","nameZh":"智能预约短期会话","domain":"booking_agent","jpa":true,"fields":["id","session_id","customer_user_id","store_id","status","draft_json","draft_version","entry_source","input_modality","expires_at","create_time","update_time"],"systems":["Backend Core","Customer Experience FE"],"code":"backend/src/main/java/com/petstore/bookingagent/domain/BookingAgentSession.java; backend/src/main/java/com/petstore/bookingagent/mapper/BookingAgentSessionMapper.java","doc":"docs/ontology/objects.md#entity:booking_agent_session; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingAgentSessionMigrationTest; BookingAgentServiceTest; BookingAgentSessionJanitorTest","evidence":"anchored","status":"implemented","note":"M0 短期结构化草稿;不保存原文/音频/模型响应,不关联 Appointment"}
|
||||||
{"id":"action:create_booking_agent_session","type":"Action","name":"createBookingAgentSession","nameZh":"创建智能预约会话","domain":"booking_agent","inputs":["storeId","entity:current_user"],"outputs":["entity:booking_agent_session","event:booking_agent_started"],"entrypoints":["planned POST /api/booking-agent/sessions"],"appliesRules":["rule:BR-AUTH-001","rule:BR-BA-001","rule:BR-BA-003","rule:BR-BA-005","rule:BR-BE-001"],"code":"","doc":"docs/ontology/actions.md#action:create_booking_agent_session; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"action:create_booking_agent_session","type":"Action","name":"createBookingAgentSession","nameZh":"创建智能预约会话","domain":"booking_agent","inputs":["storeId","entity:current_user"],"outputs":["entity:booking_agent_session","event:booking_agent_started"],"entrypoints":["POST /api/booking-agent/sessions"],"appliesRules":["rule:BR-AUTH-001","rule:BR-BA-001","rule:BR-BA-003","rule:BR-BA-005","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/bookingagent/api/BookingAgentController.java; backend/src/main/java/com/petstore/bookingagent/service/BookingAgentService.java","doc":"docs/ontology/actions.md#action:create_booking_agent_session; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingAgentControllerTest; BookingAgentServiceTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"action:submit_booking_agent_message","type":"Action","name":"submitBookingAgentMessage","nameZh":"提交智能预约消息","domain":"booking_agent","inputs":["entity:booking_agent_session","entity:current_user","draftVersion","inputType","text"],"outputs":["entity:booking_agent_session","event:booking_agent_draft_ready"],"entrypoints":["planned POST /api/booking-agent/sessions/{sessionId}/messages"],"appliesRules":["rule:BR-AUTH-001","rule:BR-BA-001","rule:BR-BA-002","rule:BR-BA-003","rule:BR-BA-004","rule:BR-BA-005","rule:BR-BE-001"],"code":"","doc":"docs/ontology/actions.md#action:submit_booking_agent_message; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"action:submit_booking_agent_message","type":"Action","name":"submitBookingAgentMessage","nameZh":"提交智能预约消息","domain":"booking_agent","inputs":["entity:booking_agent_session","entity:current_user","draftVersion","inputType","text"],"outputs":["entity:booking_agent_session","event:booking_agent_draft_ready"],"entrypoints":["POST /api/booking-agent/sessions/{sessionId}/messages"],"appliesRules":["rule:BR-AUTH-001","rule:BR-BA-001","rule:BR-BA-002","rule:BR-BA-003","rule:BR-BA-004","rule:BR-BA-005","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/bookingagent/api/BookingAgentController.java; backend/src/main/java/com/petstore/bookingagent/service/BookingAgentService.java; backend/src/main/java/com/petstore/bookingagent/service/BookingAgentContextResolver.java","doc":"docs/ontology/actions.md#action:submit_booking_agent_message; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingAgentControllerTest; BookingAgentServiceTest; BookingAgentContextResolverTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"action:transcribe_booking_agent_audio","type":"Action","name":"transcribeBookingAgentAudio","nameZh":"转写智能预约语音","domain":"booking_agent","inputs":["entity:booking_agent_session","entity:current_user","audio"],"outputs":["editableText"],"entrypoints":["planned POST /api/booking-agent/sessions/{sessionId}/transcriptions"],"appliesRules":["rule:BR-AUTH-001","rule:BR-BA-001","rule:BR-BA-004","rule:BR-BA-005"],"code":"","doc":"docs/ontology/actions.md#action:transcribe_booking_agent_audio; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"action:transcribe_booking_agent_audio","type":"Action","name":"transcribeBookingAgentAudio","nameZh":"转写智能预约语音","domain":"booking_agent","inputs":["entity:booking_agent_session","entity:current_user","audio"],"outputs":["editableText"],"entrypoints":["POST /api/booking-agent/sessions/{sessionId}/transcriptions"],"appliesRules":["rule:BR-AUTH-001","rule:BR-BA-001","rule:BR-BA-004","rule:BR-BA-005"],"code":"backend/src/main/java/com/petstore/bookingagent/api/BookingAgentController.java; backend/src/main/java/com/petstore/bookingagent/service/BookingAgentAudioValidator.java","doc":"docs/ontology/actions.md#action:transcribe_booking_agent_audio; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingAgentControllerTest; BookingAgentAudioValidatorTest; BookingAgentServiceTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"action:handoff_booking_agent_draft","type":"Action","name":"handoffBookingAgentDraft","nameZh":"交接智能预约草稿","domain":"booking_agent","inputs":["entity:booking_agent_session","entity:current_user","draftVersion"],"outputs":["entity:booking_agent_session","event:booking_agent_fallback"],"entrypoints":["planned POST /api/booking-agent/sessions/{sessionId}/fallback"],"appliesRules":["rule:BR-AUTH-001","rule:BR-BA-001","rule:BR-BA-003","rule:BR-BA-004","rule:BR-BA-005","rule:BR-BE-001"],"code":"","doc":"docs/ontology/actions.md#action:handoff_booking_agent_draft; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"action:handoff_booking_agent_draft","type":"Action","name":"handoffBookingAgentDraft","nameZh":"交接智能预约草稿","domain":"booking_agent","inputs":["entity:booking_agent_session","entity:current_user","draftVersion"],"outputs":["entity:booking_agent_session","event:booking_agent_fallback"],"entrypoints":["POST /api/booking-agent/sessions/{sessionId}/fallback"],"appliesRules":["rule:BR-AUTH-001","rule:BR-BA-001","rule:BR-BA-003","rule:BR-BA-004","rule:BR-BA-005","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/bookingagent/api/BookingAgentController.java; backend/src/main/java/com/petstore/bookingagent/service/BookingAgentService.java","doc":"docs/ontology/actions.md#action:handoff_booking_agent_draft; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingAgentControllerTest; BookingAgentServiceTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"action:cancel_booking_agent_session","type":"Action","name":"cancelBookingAgentSession","nameZh":"结束智能预约会话","domain":"booking_agent","inputs":["entity:booking_agent_session","entity:current_user"],"outputs":["entity:booking_agent_session"],"entrypoints":["planned DELETE /api/booking-agent/sessions/{sessionId}"],"appliesRules":["rule:BR-AUTH-001","rule:BR-BA-001","rule:BR-BA-003"],"code":"","doc":"docs/ontology/actions.md#action:cancel_booking_agent_session; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"action:cancel_booking_agent_session","type":"Action","name":"cancelBookingAgentSession","nameZh":"结束智能预约会话","domain":"booking_agent","inputs":["entity:booking_agent_session","entity:current_user"],"outputs":["entity:booking_agent_session"],"entrypoints":["DELETE /api/booking-agent/sessions/{sessionId}"],"appliesRules":["rule:BR-AUTH-001","rule:BR-BA-001","rule:BR-BA-003"],"code":"backend/src/main/java/com/petstore/bookingagent/api/BookingAgentController.java; backend/src/main/java/com/petstore/bookingagent/service/BookingAgentService.java","doc":"docs/ontology/actions.md#action:cancel_booking_agent_session; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingAgentControllerTest; BookingAgentServiceTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"event:booking_agent_started","type":"Event","name":"BookingAgentStarted","nameZh":"智能预约会话已启动","domain":"booking_agent","payload":["storeId","aggregateType","aggregateId","actorUserId","actorRole","source","entrySource","occurredAt"],"emittedBy":["action:create_booking_agent_session"],"appliesRules":["rule:BR-BA-001","rule:BR-BA-004","rule:BR-BE-001"],"code":"","doc":"docs/ontology/events.md#event:booking_agent_started; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"event:booking_agent_started","type":"Event","name":"BookingAgentStarted","nameZh":"智能预约会话已启动","domain":"booking_agent","payload":["storeId","aggregateType","aggregateId","actorUserId","actorRole","source","entrySource","occurredAt"],"emittedBy":["action:create_booking_agent_session"],"appliesRules":["rule:BR-BA-001","rule:BR-BA-004","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/service/BusinessEventService.java","doc":"docs/ontology/events.md#event:booking_agent_started; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BusinessEventServiceTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"event:booking_agent_draft_ready","type":"Event","name":"BookingAgentDraftReady","nameZh":"智能预约草稿已就绪","domain":"booking_agent","payload":["storeId","aggregateType","aggregateId","actorUserId","actorRole","source","inputModality","occurredAt"],"emittedBy":["action:submit_booking_agent_message"],"appliesRules":["rule:BR-BA-002","rule:BR-BA-003","rule:BR-BA-004","rule:BR-BE-001"],"code":"","doc":"docs/ontology/events.md#event:booking_agent_draft_ready; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"event:booking_agent_draft_ready","type":"Event","name":"BookingAgentDraftReady","nameZh":"智能预约草稿已就绪","domain":"booking_agent","payload":["storeId","aggregateType","aggregateId","actorUserId","actorRole","source","inputModality","occurredAt"],"emittedBy":["action:submit_booking_agent_message"],"appliesRules":["rule:BR-BA-002","rule:BR-BA-003","rule:BR-BA-004","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/service/BusinessEventService.java","doc":"docs/ontology/events.md#event:booking_agent_draft_ready; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BusinessEventServiceTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"event:booking_agent_fallback","type":"Event","name":"BookingAgentFallback","nameZh":"智能预约已降级交接","domain":"booking_agent","payload":["storeId","aggregateType","aggregateId","actorUserId","actorRole","source","reason","occurredAt"],"emittedBy":["action:handoff_booking_agent_draft"],"appliesRules":["rule:BR-BA-003","rule:BR-BA-004","rule:BR-BA-005","rule:BR-BE-001"],"code":"","doc":"docs/ontology/events.md#event:booking_agent_fallback; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"event:booking_agent_fallback","type":"Event","name":"BookingAgentFallback","nameZh":"智能预约已降级交接","domain":"booking_agent","payload":["storeId","aggregateType","aggregateId","actorUserId","actorRole","source","reason","occurredAt"],"emittedBy":["action:handoff_booking_agent_draft"],"appliesRules":["rule:BR-BA-003","rule:BR-BA-004","rule:BR-BA-005","rule:BR-BE-001"],"code":"backend/src/main/java/com/petstore/service/BusinessEventService.java","doc":"docs/ontology/events.md#event:booking_agent_fallback; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BusinessEventServiceTest; BookingAgentServiceTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"rule:BR-BA-001","type":"Rule","name":"bookingAgentCustomerStoreBoundary","nameZh":"智能预约 customer 与门店边界","domain":"booking_agent","appliesTo":["action:create_booking_agent_session","action:submit_booking_agent_message","action:transcribe_booking_agent_audio","action:handoff_booking_agent_draft","action:cancel_booking_agent_session"],"code":"","doc":"docs/ontology/rules.md#rule:BR-BA-001; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"rule:BR-BA-001","type":"Rule","name":"bookingAgentCustomerStoreBoundary","nameZh":"智能预约 customer 与门店边界","domain":"booking_agent","appliesTo":["action:create_booking_agent_session","action:submit_booking_agent_message","action:transcribe_booking_agent_audio","action:handoff_booking_agent_draft","action:cancel_booking_agent_session"],"code":"backend/src/main/java/com/petstore/bookingagent/api/BookingAgentController.java; backend/src/main/java/com/petstore/bookingagent/mapper/BookingAgentSessionMapper.java","doc":"docs/ontology/rules.md#rule:BR-BA-001; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingAgentControllerTest; BookingAgentServiceTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"rule:BR-BA-002","type":"Rule","name":"bookingAgentModelNonAuthority","nameZh":"模型非权威与结构强校验","domain":"booking_agent","appliesTo":["action:submit_booking_agent_message"],"code":"","doc":"docs/ontology/rules.md#rule:BR-BA-002; docs/contracts/booking-intent-v1.schema.json; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"rule:BR-BA-002","type":"Rule","name":"bookingAgentModelNonAuthority","nameZh":"模型非权威与结构强校验","domain":"booking_agent","appliesTo":["action:submit_booking_agent_message"],"code":"backend/src/main/java/com/petstore/bookingagent/provider/BookingIntentValidator.java; backend/src/main/java/com/petstore/bookingagent/service/BookingAgentContextResolver.java","doc":"docs/ontology/rules.md#rule:BR-BA-002; docs/contracts/booking-intent-v1.schema.json; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingIntentValidatorTest; BookingAgentContextResolverTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"rule:BR-BA-003","type":"Rule","name":"bookingAgentStateVersionTtlNoWrite","nameZh":"会话状态版本 TTL 与无写路径","domain":"booking_agent","appliesTo":["action:create_booking_agent_session","action:submit_booking_agent_message","action:handoff_booking_agent_draft","action:cancel_booking_agent_session"],"code":"","doc":"docs/ontology/rules.md#rule:BR-BA-003; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"rule:BR-BA-003","type":"Rule","name":"bookingAgentStateVersionTtlNoWrite","nameZh":"会话状态版本 TTL 与无写路径","domain":"booking_agent","appliesTo":["action:create_booking_agent_session","action:submit_booking_agent_message","action:handoff_booking_agent_draft","action:cancel_booking_agent_session"],"code":"backend/src/main/java/com/petstore/bookingagent/service/BookingAgentService.java; backend/src/main/java/com/petstore/bookingagent/service/BookingAgentSessionJanitor.java","doc":"docs/ontology/rules.md#rule:BR-BA-003; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingAgentServiceTest; BookingAgentSessionJanitorTest; BookingAgentNoAppointmentWriteContractTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"rule:BR-BA-004","type":"Rule","name":"bookingAgentPrivacyMinimization","nameZh":"语音原文与日志最小化","domain":"booking_agent","appliesTo":["action:submit_booking_agent_message","action:transcribe_booking_agent_audio","action:handoff_booking_agent_draft"],"code":"","doc":"docs/ontology/rules.md#rule:BR-BA-004; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"rule:BR-BA-004","type":"Rule","name":"bookingAgentPrivacyMinimization","nameZh":"语音原文与日志最小化","domain":"booking_agent","appliesTo":["action:submit_booking_agent_message","action:transcribe_booking_agent_audio","action:handoff_booking_agent_draft"],"code":"backend/src/main/java/com/petstore/bookingagent/service/BookingAgentAudioValidator.java; backend/src/main/java/com/petstore/bookingagent/service/BookingAgentService.java","doc":"docs/ontology/rules.md#rule:BR-BA-004; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingAgentAudioValidatorTest; BookingAgentSensitiveLoggingContractTest; BookingAgentServiceTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"rule:BR-BA-005","type":"Rule","name":"bookingAgentDisabledRateLimitedFallback","nameZh":"默认关闭限流与可退化","domain":"booking_agent","appliesTo":["action:create_booking_agent_session","action:submit_booking_agent_message","action:transcribe_booking_agent_audio","action:handoff_booking_agent_draft"],"code":"","doc":"docs/ontology/rules.md#rule:BR-BA-005; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"","evidence":"documented","status":"planned"}
|
{"id":"rule:BR-BA-005","type":"Rule","name":"bookingAgentDisabledRateLimitedFallback","nameZh":"默认关闭限流与可退化","domain":"booking_agent","appliesTo":["action:create_booking_agent_session","action:submit_booking_agent_message","action:transcribe_booking_agent_audio","action:handoff_booking_agent_draft"],"code":"backend/src/main/java/com/petstore/bookingagent/config/BookingAgentProperties.java; backend/src/main/java/com/petstore/bookingagent/service/BookingAgentRateLimiter.java","doc":"docs/ontology/rules.md#rule:BR-BA-005; docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md","test":"BookingAgentProviderConfigurationTest; BookingAgentRateLimiterTest; BookingAgentServiceTest","evidence":"anchored","status":"implemented"}
|
||||||
{"id":"rel:user_has_booking_agent_session","type":"Relation","subject":"entity:user","predicate":"HAS","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"documented"}
|
{"id":"rel:user_has_booking_agent_session","type":"Relation","subject":"entity:user","predicate":"HAS","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"anchored"}
|
||||||
{"id":"rel:store_has_booking_agent_session","type":"Relation","subject":"entity:store","predicate":"HAS","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"documented"}
|
{"id":"rel:store_has_booking_agent_session","type":"Relation","subject":"entity:store","predicate":"HAS","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"anchored"}
|
||||||
{"id":"rel:create_booking_agent_session_creates_session","type":"Relation","subject":"action:create_booking_agent_session","predicate":"CREATES","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"documented"}
|
{"id":"rel:create_booking_agent_session_creates_session","type":"Relation","subject":"action:create_booking_agent_session","predicate":"CREATES","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"anchored"}
|
||||||
{"id":"rel:submit_booking_agent_message_updates_session","type":"Relation","subject":"action:submit_booking_agent_message","predicate":"UPDATES","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"documented"}
|
{"id":"rel:submit_booking_agent_message_updates_session","type":"Relation","subject":"action:submit_booking_agent_message","predicate":"UPDATES","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"anchored"}
|
||||||
{"id":"rel:transcribe_booking_agent_audio_reads_session","type":"Relation","subject":"action:transcribe_booking_agent_audio","predicate":"READS","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"documented"}
|
{"id":"rel:transcribe_booking_agent_audio_reads_session","type":"Relation","subject":"action:transcribe_booking_agent_audio","predicate":"READS","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"anchored"}
|
||||||
{"id":"rel:handoff_booking_agent_draft_updates_session","type":"Relation","subject":"action:handoff_booking_agent_draft","predicate":"UPDATES","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"documented"}
|
{"id":"rel:handoff_booking_agent_draft_updates_session","type":"Relation","subject":"action:handoff_booking_agent_draft","predicate":"UPDATES","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"anchored"}
|
||||||
{"id":"rel:cancel_booking_agent_session_updates_session","type":"Relation","subject":"action:cancel_booking_agent_session","predicate":"UPDATES","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"documented"}
|
{"id":"rel:cancel_booking_agent_session_updates_session","type":"Relation","subject":"action:cancel_booking_agent_session","predicate":"UPDATES","object":"entity:booking_agent_session","domain":"booking_agent","evidence":"anchored"}
|
||||||
{"id":"rel:create_booking_agent_session_emits_started","type":"Relation","subject":"action:create_booking_agent_session","predicate":"EMITS","object":"event:booking_agent_started","domain":"booking_agent","evidence":"documented"}
|
{"id":"rel:create_booking_agent_session_emits_started","type":"Relation","subject":"action:create_booking_agent_session","predicate":"EMITS","object":"event:booking_agent_started","domain":"booking_agent","evidence":"anchored"}
|
||||||
{"id":"rel:submit_booking_agent_message_emits_draft_ready","type":"Relation","subject":"action:submit_booking_agent_message","predicate":"EMITS","object":"event:booking_agent_draft_ready","domain":"booking_agent","evidence":"documented"}
|
{"id":"rel:submit_booking_agent_message_emits_draft_ready","type":"Relation","subject":"action:submit_booking_agent_message","predicate":"EMITS","object":"event:booking_agent_draft_ready","domain":"booking_agent","evidence":"anchored"}
|
||||||
{"id":"rel:handoff_booking_agent_draft_emits_fallback","type":"Relation","subject":"action:handoff_booking_agent_draft","predicate":"EMITS","object":"event:booking_agent_fallback","domain":"booking_agent","evidence":"documented"}
|
{"id":"rel:handoff_booking_agent_draft_emits_fallback","type":"Relation","subject":"action:handoff_booking_agent_draft","predicate":"EMITS","object":"event:booking_agent_fallback","domain":"booking_agent","evidence":"anchored"}
|
||||||
|
|||||||
@ -61,7 +61,7 @@ rel:subject_predicate_object # rel:report_belongs_to_appointment
|
|||||||
|
|
||||||
已覆盖 P0 主闭环实体与动作,并补录:`Pet`、`ServiceType`、`ScheduleBlock`、`HighlightVideo`、`SessionToken`、`ReportImage`、`ReportTestimonial`、`ServiceInterval`、`HighlightFailReason`、`CurrentUser`、`FollowUpTask`,以及成片/上传/鉴权/寄语/退订/回访状态机/真实再次预约相关规则。
|
已覆盖 P0 主闭环实体与动作,并补录:`Pet`、`ServiceType`、`ScheduleBlock`、`HighlightVideo`、`SessionToken`、`ReportImage`、`ReportTestimonial`、`ServiceInterval`、`HighlightFailReason`、`CurrentUser`、`FollowUpTask`,以及成片/上传/鉴权/寄语/退订/回访状态机/真实再次预约相关规则。
|
||||||
|
|
||||||
**智能预约助手 M0** 已以 `documented` 证据录入 `BookingAgentSession`、5 个动作、3 个漏斗事件、`BR-BA-001..005` 和 10 条关系。它们表示 Batch 0 契约已冻结,**不表示代码已实现**;五个计划 endpoint 以 `planned METHOD /path` 录入,实现时必须与代码、测试同批转为 `anchored`。
|
**智能预约助手 M0 Batch 2** 已以 `anchored` 证据录入真实 JPA `BookingAgentSession`、5 个只读编排动作、3 个低敏漏斗事件、`BR-BA-001..005` 和 10 条关系。五个 endpoint 已按冻结 OpenAPI 注册;`/confirm` 与 Appointment 写路径仍明确不存在,供应商开关默认关闭。
|
||||||
|
|
||||||
**门店 Web 后台 Phase A**:`AdminConsole`、`Workbench`、`WorkbenchTodoItem` 仍是非 JPA 读模型;`StoreCustomer` 与 `FollowUpTask` 已落为 JPA 稳定业务对象。`BR-ADMIN-001`…`004`、`BR-FU-001/002` 与 admin actions 继续约束后台;收银/会员资产仍为 gap。
|
**门店 Web 后台 Phase A**:`AdminConsole`、`Workbench`、`WorkbenchTodoItem` 仍是非 JPA 读模型;`StoreCustomer` 与 `FollowUpTask` 已落为 JPA 稳定业务对象。`BR-ADMIN-001`…`004`、`BR-FU-001/002` 与 admin actions 继续约束后台;收银/会员资产仍为 gap。
|
||||||
|
|
||||||
|
|||||||
@ -716,51 +716,56 @@ legacy 永久邀请码查询入口已停用,固定返回 `410 / LEGACY_INVITE_
|
|||||||
- **适用规则**:`rule:BR-ADMIN-001`、`rule:BR-ADMIN-002`、`rule:BR-SCH-001`
|
- **适用规则**:`rule:BR-ADMIN-001`、`rule:BR-ADMIN-002`、`rule:BR-SCH-001`
|
||||||
- **证据**:`anchored`
|
- **证据**:`anchored`
|
||||||
|
|
||||||
## 智能预约助手 M0(Batch 0 · documented)
|
## 智能预约助手 M0(Batch 2 · anchored)
|
||||||
|
|
||||||
> 下列入口已冻结但尚未注册;机器图以 `planned METHOD /path` 标识,不得误报为已实现 endpoint。
|
> 下列五个入口已按冻结 OpenAPI 注册;仍不存在 `/confirm`,不进入 Appointment 写路径。
|
||||||
|
|
||||||
### action:create_booking_agent_session
|
### action:create_booking_agent_session
|
||||||
|
|
||||||
使用已选有效 `storeId` 为当前 customer 创建短期会话,并首次记录 `booking_agent_started`。
|
使用已选有效 `storeId` 为当前 customer 创建短期会话,并首次记录 `booking_agent_started`。
|
||||||
|
|
||||||
- **计划入口**:`POST /api/booking-agent/sessions`
|
- **入口**:`POST /api/booking-agent/sessions`
|
||||||
- **输出**:`entity:booking_agent_session`
|
- **输出**:`entity:booking_agent_session`
|
||||||
- **规则**:`rule:BR-AUTH-001`、`rule:BR-BA-001`、`rule:BR-BA-003`、`rule:BR-BA-005`、`rule:BR-BE-001`
|
- **规则**:`rule:BR-AUTH-001`、`rule:BR-BA-001`、`rule:BR-BA-003`、`rule:BR-BA-005`、`rule:BR-BE-001`
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BookingAgentController#createSession`、`BookingAgentService#createSession`;`BookingAgentControllerTest`、`BookingAgentServiceTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
### action:submit_booking_agent_message
|
### action:submit_booking_agent_message
|
||||||
|
|
||||||
在 `sessionId + current.userId` 范围内校验草稿版本,将当轮文字解析为非权威约束,再由后端解析真实宠物、服务与号源。
|
在 `sessionId + current.userId` 范围内校验草稿版本,将当轮文字解析为非权威约束,再由后端解析真实宠物、服务与号源。
|
||||||
|
|
||||||
- **计划入口**:`POST /api/booking-agent/sessions/{sessionId}/messages`
|
- **入口**:`POST /api/booking-agent/sessions/{sessionId}/messages`
|
||||||
- **输入/输出**:`entity:booking_agent_session`、`draftVersion`、`inputType`、`text`
|
- **输入/输出**:`entity:booking_agent_session`、`draftVersion`、`inputType`、`text`
|
||||||
- **规则**:`rule:BR-BA-001` … `rule:BR-BA-005`
|
- **规则**:`rule:BR-BA-001` … `rule:BR-BA-005`
|
||||||
- **触发事件**:首次进入 `confirmable` 时 `event:booking_agent_draft_ready`
|
- **触发事件**:首次进入 `confirmable` 时 `event:booking_agent_draft_ready`
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BookingAgentController#submitMessage`、`BookingAgentService#submitMessage`、`BookingAgentContextResolver`;`BookingAgentServiceTest`、`BookingAgentContextResolverTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
### action:transcribe_booking_agent_audio
|
### action:transcribe_booking_agent_audio
|
||||||
|
|
||||||
在本人未终止 session 下将短音频转为可编辑文字,不自动进入意图处理。
|
在本人未终止 session 下将短音频转为可编辑文字,不自动进入意图处理。
|
||||||
|
|
||||||
- **计划入口**:`POST /api/booking-agent/sessions/{sessionId}/transcriptions`
|
- **入口**:`POST /api/booking-agent/sessions/{sessionId}/transcriptions`
|
||||||
- **规则**:`rule:BR-BA-001`、`rule:BR-BA-004`、`rule:BR-BA-005`
|
- **规则**:`rule:BR-BA-001`、`rule:BR-BA-004`、`rule:BR-BA-005`
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BookingAgentController#transcribe`、`BookingAgentAudioValidator`;`BookingAgentControllerTest`、`BookingAgentAudioValidatorTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
### action:handoff_booking_agent_draft
|
### action:handoff_booking_agent_draft
|
||||||
|
|
||||||
返回服务端验证的部分或完整草稿,将会话转为 `fallback`,由现有表单承担最终提交。
|
返回服务端验证的部分或完整草稿,将会话转为 `fallback`,由现有表单承担最终提交。
|
||||||
|
|
||||||
- **计划入口**:`POST /api/booking-agent/sessions/{sessionId}/fallback`
|
- **入口**:`POST /api/booking-agent/sessions/{sessionId}/fallback`
|
||||||
- **输出**:一次性草稿交接对象
|
- **输出**:一次性草稿交接对象
|
||||||
- **规则**:`rule:BR-BA-001`、`rule:BR-BA-003`、`rule:BR-BA-005`
|
- **规则**:`rule:BR-BA-001`、`rule:BR-BA-003`、`rule:BR-BA-005`
|
||||||
- **触发事件**:`event:booking_agent_fallback`
|
- **触发事件**:`event:booking_agent_fallback`
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BookingAgentController#handoff`、`BookingAgentService#handoff`;`BookingAgentControllerTest`、`BookingAgentServiceTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
### action:cancel_booking_agent_session
|
### action:cancel_booking_agent_session
|
||||||
|
|
||||||
由当前 customer 结束本人未终止会话,仅将 session 标记为 `cancelled`。
|
由当前 customer 结束本人未终止会话,仅将 session 标记为 `cancelled`。
|
||||||
|
|
||||||
- **计划入口**:`DELETE /api/booking-agent/sessions/{sessionId}`
|
- **入口**:`DELETE /api/booking-agent/sessions/{sessionId}`
|
||||||
- **规则**:`rule:BR-BA-001`、`rule:BR-BA-003`
|
- **规则**:`rule:BR-BA-001`、`rule:BR-BA-003`
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BookingAgentController#cancel`、`BookingAgentService#cancel`;`BookingAgentControllerTest`、`BookingAgentServiceTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|||||||
@ -338,7 +338,7 @@
|
|||||||
- **payload**:`storeId`、`userId`、`ts`
|
- **payload**:`storeId`、`userId`、`ts`
|
||||||
- **证据**:`gap`(A 期可不实现上报)
|
- **证据**:`gap`(A 期可不实现上报)
|
||||||
|
|
||||||
## 智能预约助手 M0(Batch 0 · documented)
|
## 智能预约助手 M0(Batch 2 · anchored)
|
||||||
|
|
||||||
### event:booking_agent_started
|
### event:booking_agent_started
|
||||||
|
|
||||||
@ -348,7 +348,8 @@
|
|||||||
- **幂等键**:`booking_agent_started:{sessionDbId}`
|
- **幂等键**:`booking_agent_started:{sessionDbId}`
|
||||||
- **BusinessEvent**:`storeId=session.storeId`、`aggregateType=booking_agent_session`、`aggregateId=session.id`
|
- **BusinessEvent**:`storeId=session.storeId`、`aggregateType=booking_agent_session`、`aggregateId=session.id`
|
||||||
- **metadata 白名单**:`entrySource`
|
- **metadata 白名单**:`entrySource`
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BusinessEventService#recordBookingAgentStarted`;`BusinessEventServiceTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
### event:booking_agent_draft_ready
|
### event:booking_agent_draft_ready
|
||||||
|
|
||||||
@ -357,7 +358,8 @@ session 首次进入 `confirmable` 的事实,不表示预约已创建。
|
|||||||
- **触发动作**:`action:submit_booking_agent_message`
|
- **触发动作**:`action:submit_booking_agent_message`
|
||||||
- **幂等键**:`booking_agent_draft_ready:{sessionDbId}`
|
- **幂等键**:`booking_agent_draft_ready:{sessionDbId}`
|
||||||
- **metadata 白名单**:`inputModality`
|
- **metadata 白名单**:`inputModality`
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BusinessEventService#recordBookingAgentDraftReady`;`BusinessEventServiceTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
### event:booking_agent_fallback
|
### event:booking_agent_fallback
|
||||||
|
|
||||||
@ -366,6 +368,7 @@ session 首次进入 `confirmable` 的事实,不表示预约已创建。
|
|||||||
- **触发动作**:`action:handoff_booking_agent_draft`
|
- **触发动作**:`action:handoff_booking_agent_draft`
|
||||||
- **幂等键**:`booking_agent_fallback:{sessionDbId}`
|
- **幂等键**:`booking_agent_fallback:{sessionDbId}`
|
||||||
- **metadata 白名单**:`reason=user/llm_unavailable`
|
- **metadata 白名单**:`reason=user/llm_unavailable`
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BusinessEventService#recordBookingAgentFallback`;`BusinessEventServiceTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
M0 三个事件均禁止写入输入原文、转写文本、备注、宠物名、服务名、供应商 request ID 或错误原文;M0 不定义 `booking_agent_confirmed`。
|
M0 三个事件均禁止写入输入原文、转写文本、备注、宠物名、服务名、供应商 request ID 或错误原文;M0 不定义 `booking_agent_confirmed`。
|
||||||
|
|||||||
@ -543,7 +543,7 @@ API 动态聚合字段:`pets`、`lastVisitAt`、`lastReportId`、`leadStatus`
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 智能预约助手 M0(Batch 0 契约)
|
## 智能预约助手 M0(Batch 2 已实现)
|
||||||
|
|
||||||
## entity:booking_agent_session
|
## entity:booking_agent_session
|
||||||
|
|
||||||
@ -563,7 +563,10 @@ API 动态聚合字段:`pets`、`lastVisitAt`、`lastReportId`、`leadStatus`
|
|||||||
| `create_time / update_time` | 服务端审计时间 |
|
| `create_time / update_time` | 服务端审计时间 |
|
||||||
|
|
||||||
- **不存储**:原始语音、转写原文、完整对话、提示词、模型原始请求/响应、`appointment_id`。
|
- **不存储**:原始语音、转写原文、完整对话、提示词、模型原始请求/响应、`appointment_id`。
|
||||||
- **归属系统**:Backend Core(计划 `bookingagent` 包)。
|
- **归属系统**:Backend Core(`bookingagent` 包)。
|
||||||
|
- **代码**:`backend/src/main/java/com/petstore/bookingagent/domain/BookingAgentSession.java`、`mapper/BookingAgentSessionMapper.java`。
|
||||||
|
- **迁移**:`backend/db/migrations/20260802_create_booking_agent_session.sql`。
|
||||||
|
- **测试**:`BookingAgentSessionMigrationTest`、`BookingAgentServiceTest`、`BookingAgentSessionJanitorTest`。
|
||||||
- **文档**:`docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md`。
|
- **文档**:`docs/架构决策-智能预约助手M0契约与数据模型-2026-08-02.md`。
|
||||||
- **证据**:`documented`(尚未创建 JPA 实体,机器图临时 `jpa:false`;实现批必须切换为真实 JPA 证据)。
|
- **证据**:`anchored`(真实 JPA 实体、迁移、owner 查询与 TTL 清理测试)。
|
||||||
- **约束**:`rule:BR-BA-001` … `rule:BR-BA-005`。
|
- **约束**:`rule:BR-BA-001` … `rule:BR-BA-005`。
|
||||||
|
|||||||
@ -188,7 +188,7 @@
|
|||||||
| `view_store_customer_timeline` READS `store_customer` / `business_event` | 同店校验后分页读取主档与事实 |
|
| `view_store_customer_timeline` READS `store_customer` / `business_event` | 同店校验后分页读取主档与事实 |
|
||||||
| `admin_list_leads` READS `follow_up_task` | `/leads` 导航承载真实操作任务池,不直接编辑留资事实 |
|
| `admin_list_leads` READS `follow_up_task` | `/leads` 导航承载真实操作任务池,不直接编辑留资事实 |
|
||||||
|
|
||||||
## 智能预约助手 M0 关系(Batch 0 · documented)
|
## 智能预约助手 M0 关系(Batch 2 · anchored)
|
||||||
|
|
||||||
| 关系 | 说明 |
|
| 关系 | 说明 |
|
||||||
|------|------|
|
|------|------|
|
||||||
|
|||||||
@ -384,7 +384,7 @@
|
|||||||
|
|
||||||
### rule:BR-CONFIG-003
|
### rule:BR-CONFIG-003
|
||||||
|
|
||||||
**生产发布只读门禁**:正式切流前必须按固定顺序完成备份和八个版本化迁移,再以最终生产配置运行 JPA schema `validate` 与 31 项只读数据不变量检查。运行期 readiness 必须同时覆盖数据库、磁盘、上传目录和 FFmpeg/ffprobe;上线自动 smoke 只允许 GET,不创建或修改业务数据,并验证 CORS allow/deny。
|
**生产发布只读门禁**:正式切流前必须完成备份,并按固定顺序执行目标版本包含的全部版本化迁移,再以最终生产配置运行 JPA schema `validate` 与 31 项只读数据不变量检查。运行期 readiness 必须同时覆盖数据库、磁盘、上传目录和 FFmpeg/ffprobe;上线自动 smoke 只允许 GET,不创建或修改业务数据,并验证 CORS allow/deny。
|
||||||
|
|
||||||
- **适用动作**:—(发布全局约束)
|
- **适用动作**:—(发布全局约束)
|
||||||
- **代码**:`backend/src/main/java/com/petstore/config/ProductionDatabasePreflightRunner.java`、`PetstoreRuntimeHealthIndicator.java`、`backend/deploy/release-preflight.sh`、`production-smoke.sh`
|
- **代码**:`backend/src/main/java/com/petstore/config/ProductionDatabasePreflightRunner.java`、`PetstoreRuntimeHealthIndicator.java`、`backend/deploy/release-preflight.sh`、`production-smoke.sh`
|
||||||
@ -480,39 +480,44 @@
|
|||||||
- **测试**:`BusinessEventServiceTest`、`BusinessEventMigrationTest`、`AdminBusinessEventControllerTest`
|
- **测试**:`BusinessEventServiceTest`、`BusinessEventMigrationTest`、`AdminBusinessEventControllerTest`
|
||||||
- **证据**:`anchored`
|
- **证据**:`anchored`
|
||||||
|
|
||||||
## 智能预约助手 M0(Batch 0 · documented)
|
## 智能预约助手 M0(Batch 2 · anchored)
|
||||||
|
|
||||||
### rule:BR-BA-001
|
### rule:BR-BA-001
|
||||||
|
|
||||||
**customer 与门店数据边界**:所有 endpoint 只允许已登录 customer;session 每次以 `sessionId + current.userId` 查询;他人与不存在 session 同样返回 `SESSION_NOT_FOUND`。`storeId` 只在创建时验证,后续不可覆盖。
|
**customer 与门店数据边界**:所有 endpoint 只允许已登录 customer;session 每次以 `sessionId + current.userId` 查询;他人与不存在 session 同样返回 `SESSION_NOT_FOUND`。`storeId` 只在创建时验证,后续不可覆盖。
|
||||||
|
|
||||||
- **适用动作**:M0 全部五个动作
|
- **适用动作**:M0 全部五个动作
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BookingAgentController`、`BookingAgentSessionMapper#findOwnedForUpdate`;`BookingAgentControllerTest`、`BookingAgentServiceTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
### rule:BR-BA-002
|
### rule:BR-BA-002
|
||||||
|
|
||||||
**模型非权威与结构强校验**:模型只返回通过 `booking-intent-v1` 的文本约束,未知字段拒绝。宠物、服务、日期时间和号源由后端确定性重新解析;模型不得产生 ID、价格、号源或预约状态事实。
|
**模型非权威与结构强校验**:模型只返回通过 `booking-intent-v1` 的文本约束,未知字段拒绝。宠物、服务、日期时间和号源由后端确定性重新解析;模型不得产生 ID、价格、号源或预约状态事实。
|
||||||
|
|
||||||
- **适用动作**:`action:submit_booking_agent_message`
|
- **适用动作**:`action:submit_booking_agent_message`
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BookingIntentValidator`、`BookingAgentIntentMerger`、`BookingAgentContextResolver`;对应 provider/context 测试
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
### rule:BR-BA-003
|
### rule:BR-BA-003
|
||||||
|
|
||||||
**状态、版本、TTL 与无写路径**:M0 只允许六个会话状态,草稿更新必须校验 `draftVersion`;TTL 固定 30 分钟且不滑动续期,过期 24 小时后物理清理。M0 不注册 `/confirm`、不调用预约写服务、不修改 `Appointment`。
|
**状态、版本、TTL 与无写路径**:M0 只允许六个会话状态,草稿更新必须校验 `draftVersion`;TTL 固定 30 分钟且不滑动续期,过期 24 小时后物理清理。M0 不注册 `/confirm`、不调用预约写服务、不修改 `Appointment`。
|
||||||
|
|
||||||
- **适用动作**:创建、提交消息、草稿交接、结束会话
|
- **适用动作**:创建、提交消息、草稿交接、结束会话
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BookingAgentService`、`BookingAgentSessionJanitor`;`BookingAgentServiceTest`、`BookingAgentSessionJanitorTest`、`BookingAgentNoAppointmentWriteContractTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
### rule:BR-BA-004
|
### rule:BR-BA-004
|
||||||
|
|
||||||
**语音、原文与日志最小化**:原始语音、当轮用户原文、完整对话、提示词和模型原始请求/响应不落库、不进事件、不进日志。音频最多 60 秒/3 MB,转写完立即释放,且必须经用户编辑/确认后才发消息。
|
**语音、原文与日志最小化**:原始语音、当轮用户原文、完整对话、提示词和模型原始请求/响应不落库、不进事件、不进日志。音频最多 60 秒/3 MB,转写完立即释放,且必须经用户编辑/确认后才发消息。
|
||||||
|
|
||||||
- **适用动作**:提交消息、语音转写、草稿交接
|
- **适用动作**:提交消息、语音转写、草稿交接
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BookingAgentAudioValidator`、`BookingAgentService#transcribe`;`BookingAgentAudioValidatorTest`、`BookingAgentSensitiveLoggingContractTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|
||||||
### rule:BR-BA-005
|
### rule:BR-BA-005
|
||||||
|
|
||||||
**默认关闭、限流与可退化**:`PETSTORE_BOOKING_AGENT_ENABLED` 默认 `false`。每 customer 10 分钟内最多创建 5 会话、30 条消息、10 段语音;模型/ASR/外部查询失败时保留已验证草稿并退回普通表单,不影响普通预约。单实例进程内限流只是 M0 临时边界,多实例前必须改为共享状态。
|
**默认关闭、限流与可退化**:`PETSTORE_BOOKING_AGENT_ENABLED` 默认 `false`。每 customer 10 分钟内最多创建 5 会话、30 条消息、10 段语音;模型/ASR/外部查询失败时保留已验证草稿并退回普通表单,不影响普通预约。单实例进程内限流只是 M0 临时边界,多实例前必须改为共享状态。
|
||||||
|
|
||||||
- **适用动作**:创建会话、提交消息、语音转写、草稿交接
|
- **适用动作**:创建会话、提交消息、语音转写、草稿交接
|
||||||
- **证据**:`documented`
|
- **代码/测试**:`BookingAgentProperties`、`BookingAgentRateLimiter`、provider 错误映射;`BookingAgentProviderConfigurationTest`、`BookingAgentRateLimiterTest`、`BookingAgentServiceTest`
|
||||||
|
- **证据**:`anchored`
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# 智能预约助手 M0 执行队列
|
# 智能预约助手 M0 执行队列
|
||||||
|
|
||||||
> 日期:2026-08-02<br>
|
> 日期:2026-08-02<br>
|
||||||
> 状态:**Batch 1 provider adaptation completed / Batch 2 ready**<br>
|
> 状态:**Batch 2 session orchestration completed / Batch 3 ready**<br>
|
||||||
> RC Included:`No`<br>
|
> RC Included:`No`<br>
|
||||||
> 当前优先级说明:不抢占 `phase2-pilot-rc6` 真实门店基线问题;按独立 feature flag 开发
|
> 当前优先级说明:不抢占 `phase2-pilot-rc6` 真实门店基线问题;按独立 feature flag 开发
|
||||||
|
|
||||||
@ -17,7 +17,7 @@
|
|||||||
| Task Name | Owner Agent | Status | Depends On |
|
| Task Name | Owner Agent | Status | Depends On |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 实现智能预约供应商适配与契约测试 | Backend Core | Done | Batch 0 冻结资产 |
|
| 实现智能预约供应商适配与契约测试 | Backend Core | Done | Batch 0 冻结资产 |
|
||||||
| 实现智能预约会话与只读预约编排 | Backend Core | Ready | Batch 0 冻结资产;provider interface |
|
| 实现智能预约会话与只读预约编排 | Backend Core | Done | Batch 0 冻结资产;provider interface |
|
||||||
| 实现宠主一句话预约与草稿回填 | Customer Experience FE | Ready | OpenAPI;可先用 mock |
|
| 实现宠主一句话预约与草稿回填 | Customer Experience FE | Ready | OpenAPI;可先用 mock |
|
||||||
| 验收智能预约 M0 草稿链路 | Core Flow QA | Ready | 可先写 fixture/smoke;执行依赖前三项 |
|
| 验收智能预约 M0 草稿链路 | Core Flow QA | Ready | 可先写 fixture/smoke;执行依赖前三项 |
|
||||||
| 完成真实供应商对照与生产隐私复核 | Backend Ops | Blocked | 云账号、密钥、授权语音和上线授权 |
|
| 完成真实供应商对照与生产隐私复核 | Backend Ops | Blocked | 云账号、密钥、授权语音和上线授权 |
|
||||||
@ -71,7 +71,7 @@
|
|||||||
| Paired QA | `Core Flow QA` |
|
| Paired QA | `Core Flow QA` |
|
||||||
| Workstream | `Core Booking Flow` |
|
| Workstream | `Core Booking Flow` |
|
||||||
| Track | `Coding` |
|
| Track | `Coding` |
|
||||||
| Status | `Ready` |
|
| Status | `Done — 2026-08-02` |
|
||||||
| Priority | `P0` |
|
| Priority | `P0` |
|
||||||
| Repo/Path | `backend/src/main/java/com/petstore/bookingagent`、`backend/db/migrations/20260802_create_booking_agent_session.sql` |
|
| Repo/Path | `backend/src/main/java/com/petstore/bookingagent`、`backend/db/migrations/20260802_create_booking_agent_session.sql` |
|
||||||
| Service Lock | `backend:booking-agent-session+appointment-read-tools` |
|
| Service Lock | `backend:booking-agent-session+appointment-read-tools` |
|
||||||
@ -79,11 +79,11 @@
|
|||||||
| Acceptance | 五个 endpoint;customer 归属;六态状态机;draftVersion;30 分钟 TTL/24 小时清理;只读宠物/服务/容量;三个低敏事件;不存在 `/confirm` |
|
| Acceptance | 五个 endpoint;customer 归属;六态状态机;draftVersion;30 分钟 TTL/24 小时清理;只读宠物/服务/容量;三个低敏事件;不存在 `/confirm` |
|
||||||
| RC Included | `No` |
|
| RC Included | `No` |
|
||||||
| Due Date | `TBD` |
|
| Due Date | `TBD` |
|
||||||
| Output Link | `TBD — implementation commit` |
|
| Output Link | [`petstore-backend@3c00065`](https://git.s-good.com/petstore/petstore-backend/commit/3c00065) |
|
||||||
| Blocker Owner | `None` |
|
| Blocker Owner | `None` |
|
||||||
| Commit / RC | `Not Frozen` |
|
| Commit / RC | `3c00065 / RC No` |
|
||||||
| Architecture Review Required | `Yes — completed by M0 ADR` |
|
| Architecture Review Required | `Yes — completed by M0 ADR` |
|
||||||
| Data Model Review Required | `Yes — proposal completed; implementation diff requires Data Model review` |
|
| Data Model Review Required | `Yes — implementation diff completed; frozen schema unchanged` |
|
||||||
| Access / Privacy Review Required | `Yes — development boundary completed` |
|
| Access / Privacy Review Required | `Yes — development boundary completed` |
|
||||||
|
|
||||||
额外门禁:
|
额外门禁:
|
||||||
@ -94,6 +94,15 @@
|
|||||||
- 迁移包含索引、状态验证和 TTL 清理验证查询;
|
- 迁移包含索引、状态验证和 TTL 清理验证查询;
|
||||||
- 实现时同步把对应本体证据从 `documented` 更新为 `anchored`。
|
- 实现时同步把对应本体证据从 `documented` 更新为 `anchored`。
|
||||||
|
|
||||||
|
完成证据:
|
||||||
|
|
||||||
|
- 五个冻结 endpoint 已注册,全部要求 customer;session 使用 `sessionId + current.userId` 带锁查询;
|
||||||
|
- 六态、`draftVersion`、固定 30 分钟 TTL、每小时过期和 24 小时物理清理已实现;
|
||||||
|
- Pet、ServiceType、日期时间和号源均由后端在 owner/store 范围重新解析,容量查询复用现有只读模型;
|
||||||
|
- 音频按 3 MB、文件头、MIME 和 60 秒权威复核,转写不自动提交消息;
|
||||||
|
- 三个低敏 BusinessEvent 已实现,`draft_json` 不含原文、查询词、音频或模型响应;
|
||||||
|
- `mvn test`:292 tests,0 failures,0 errors;无 `/confirm`,契约测试禁止 `AppointmentMapper.save`。
|
||||||
|
|
||||||
## Task:实现宠主一句话预约与草稿回填
|
## Task:实现宠主一句话预约与草稿回填
|
||||||
|
|
||||||
| 字段 | 值 |
|
| 字段 | 值 |
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# 智能预约助手 M0 编码任务 brief
|
# 智能预约助手 M0 编码任务 brief
|
||||||
|
|
||||||
> 日期:2026-08-02<br>
|
> 日期:2026-08-02<br>
|
||||||
> 状态:**Batch 1 已完成 / Batch 2 待实施**<br>
|
> 状态:**Batch 2 已完成 / Batch 3 待实施**<br>
|
||||||
> 目标:宠主用文字或语音生成可验证预约草稿,回填现有表单,不由智能层创建 `Appointment`<br>
|
> 目标:宠主用文字或语音生成可验证预约草稿,回填现有表单,不由智能层创建 `Appointment`<br>
|
||||||
> Workstream:`Core Booking Flow`<br>
|
> Workstream:`Core Booking Flow`<br>
|
||||||
> Owner Agent:`Backend Core` + `Customer Experience FE`<br>
|
> Owner Agent:`Backend Core` + `Customer Experience FE`<br>
|
||||||
@ -324,16 +324,16 @@ M0 已冻结事件:
|
|||||||
|
|
||||||
M0 不记录 `booking_agent_confirmed`,也不修改现有 `appointment_created` metadata,因为助手没有直接确认写入,而客户端的 `source` 字符串不能当作服务端归因事实。如后续需要精确联结「助手草稿 -> 表单创建」,另立 brief 设计可验证、一次性的草稿交接机制。
|
M0 不记录 `booking_agent_confirmed`,也不修改现有 `appointment_created` metadata,因为助手没有直接确认写入,而客户端的 `source` 字符串不能当作服务端归因事实。如后续需要精确联结「助手草稿 -> 表单创建」,另立 brief 设计可验证、一次性的草稿交接机制。
|
||||||
|
|
||||||
Batch 0 已按 `documented` 证据增加:
|
Batch 0 已按 `documented` 证据增加以下设计条目;Batch 2 已用真实代码和测试将对应条目全部更新为 `anchored`:
|
||||||
|
|
||||||
- `ontology/objects.md`:`booking_agent_session` 的 `documented` 模型条目;
|
- `ontology/objects.md`:`booking_agent_session` 最初的 `documented` 模型条目;
|
||||||
- `ontology/actions.md`:创建会话、提交消息、语音转写、回填草稿、结束会话;
|
- `ontology/actions.md`:创建会话、提交消息、语音转写、回填草稿、结束会话;
|
||||||
- `ontology/events.md`:M0 三个漏斗事件;
|
- `ontology/events.md`:M0 三个漏斗事件;
|
||||||
- `ontology/rules.md`:customer 数据范围、无写工具、原始语音/原文不持久化、超时降级;
|
- `ontology/rules.md`:customer 数据范围、无写工具、原始语音/原文不持久化、超时降级;
|
||||||
- `ontology/relations.md` 与 `graph/ontology.jsonl`;
|
- `ontology/relations.md` 与 `graph/ontology.jsonl`;
|
||||||
- `coverage/ontology-coverage-audit.md`。
|
- `coverage/ontology-coverage-audit.md`。
|
||||||
|
|
||||||
实现时必须在同一批把真实代码/测试路径补入,并将对应条目从 `documented` 更新为 `anchored`;不得提前宣称已实现。
|
Batch 2 已在同一批补入真实代码/测试路径,并将对应条目从 `documented` 更新为 `anchored`;Batch 3 前端仍不得提前宣称已实现。
|
||||||
|
|
||||||
## 7. 自动化测试
|
## 7. 自动化测试
|
||||||
|
|
||||||
@ -411,6 +411,8 @@ Owner:Backend Core
|
|||||||
|
|
||||||
Owner:Backend Core
|
Owner:Backend Core
|
||||||
|
|
||||||
|
状态:**Completed — 2026-08-02(petstore-backend `3c00065`)**
|
||||||
|
|
||||||
- 实现 session 实体、迁移、mapper 和 service;
|
- 实现 session 实体、迁移、mapper 和 service;
|
||||||
- 复用 Pet、ServiceType、Store 和 BookingCapacity 领域服务;
|
- 复用 Pet、ServiceType、Store 和 BookingCapacity 领域服务;
|
||||||
- 实现确定性回复模板和 fallback DTO;
|
- 实现确定性回复模板和 fallback DTO;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# 架构决策:智能预约助手 M0 契约与数据模型
|
# 架构决策:智能预约助手 M0 契约与数据模型
|
||||||
|
|
||||||
> 日期:2026-08-02<br>
|
> 日期:2026-08-02<br>
|
||||||
> 状态:**Accepted for M0 implementation / 尚未实现**<br>
|
> 状态:**Accepted / Batch 2 implemented — petstore-backend `3c00065`**<br>
|
||||||
> Workstream:`Core Booking Flow`<br>
|
> Workstream:`Core Booking Flow`<br>
|
||||||
> Track:`Architecture`<br>
|
> Track:`Architecture`<br>
|
||||||
> Priority:`P0`(独立试验流,不高于 RC6 真实门店基线)<br>
|
> Priority:`P0`(独立试验流,不高于 RC6 真实门店基线)<br>
|
||||||
@ -9,7 +9,7 @@
|
|||||||
> Paired QA:`Core Flow QA`<br>
|
> Paired QA:`Core Flow QA`<br>
|
||||||
> Service Lock:`docs:booking-agent-m0-contract+ontology`<br>
|
> Service Lock:`docs:booking-agent-m0-contract+ontology`<br>
|
||||||
> Architecture Review Required:`Yes — completed by this ADR`<br>
|
> Architecture Review Required:`Yes — completed by this ADR`<br>
|
||||||
> Data Model Review Required:`Yes — completed for implementation proposal`<br>
|
> Data Model Review Required:`Yes — proposal and implementation diff completed`<br>
|
||||||
> Access / Privacy Review Required:`Yes — development boundary accepted; live provider and production review pending`<br>
|
> Access / Privacy Review Required:`Yes — development boundary accepted; live provider and production review pending`<br>
|
||||||
> RC Included:`No`
|
> RC Included:`No`
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ stateDiagram-v2
|
|||||||
|
|
||||||
## 6. 数据模型冻结
|
## 6. 数据模型冻结
|
||||||
|
|
||||||
计划迁移:`backend/db/migrations/20260802_create_booking_agent_session.sql`。Batch 0 只冻结设计,不在 docs 任务内创建迁移。
|
已实现迁移:`backend/db/migrations/20260802_create_booking_agent_session.sql`(petstore-backend `3c00065`)。
|
||||||
|
|
||||||
### 6.1 `t_booking_agent_session`
|
### 6.1 `t_booking_agent_session`
|
||||||
|
|
||||||
@ -263,6 +263,8 @@ M0 默认每个 customer:
|
|||||||
- 去掉 `deleted` 和 `appointment_id`;
|
- 去掉 `deleted` 和 `appointment_id`;
|
||||||
- 增加固定 TTL、物理清理和 `draft_version` 并发规则。
|
- 增加固定 TTL、物理清理和 `draft_version` 并发规则。
|
||||||
|
|
||||||
|
**实现 diff 复核通过。** `BookingAgentSession` JPA、迁移与 mapper 保持上述冻结字段和三个索引;六态与 `input_modality` 有数据库 `CHECK`,owner 查询持悲观锁,未增加 `appointment_id`、`deleted`、turn 表或原文列。迁移测试、版本/TTL/清理测试均已落地。
|
||||||
|
|
||||||
### Access / Privacy Review
|
### Access / Privacy Review
|
||||||
|
|
||||||
**开发边界通过,真实供应商 smoke 与生产开启未通过。** 不需要真实密钥即可实现接口、stub、状态机和测试;真实调用前仍需完成供应商数据处理确认、小程序隐私告知、费用告警和已知情语音样本评测。
|
**开发边界通过,真实供应商 smoke 与生产开启未通过。** 不需要真实密钥即可实现接口、stub、状态机和测试;真实调用前仍需完成供应商数据处理确认、小程序隐私告知、费用告警和已知情语音样本评测。
|
||||||
@ -293,3 +295,11 @@ M0 默认每个 customer:
|
|||||||
- 未配置密钥或 feature flag 关闭时应用正常启动、普通预约正常;
|
- 未配置密钥或 feature flag 关闭时应用正常启动、普通预约正常;
|
||||||
- 本体从 `documented` 更新为 `anchored` 只能与代码和测试同一批完成;
|
- 本体从 `documented` 更新为 `anchored` 只能与代码和测试同一批完成;
|
||||||
- 真实供应商 smoke、生产配置和 RC 纳入必须重新授权。
|
- 真实供应商 smoke、生产配置和 RC 纳入必须重新授权。
|
||||||
|
|
||||||
|
## 12. Batch 2 实现证据
|
||||||
|
|
||||||
|
- Backend:`3c00065 feat: add booking agent session orchestration`;
|
||||||
|
- 五个 endpoint、JPA 会话、迁移、owner/store 数据边界、版本与 TTL 已实现;
|
||||||
|
- 本体 `BookingAgentSession`、五个动作、三个事件、五条规则和十条关系已从 `documented` 更新为 `anchored`;
|
||||||
|
- 后端全量测试 292 项通过,本体端点 73/73、JPA 实体 17/17,无漂移;
|
||||||
|
- 功能开关仍默认关闭,真实供应商 smoke、Batch 3 前端和生产开启仍未完成。
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
| Priority | P0 |
|
| Priority | P0 |
|
||||||
| Repo/Path | `backend/deploy/**`、前端发布配置、`docs/**` |
|
| Repo/Path | `backend/deploy/**`、前端发布配置、`docs/**` |
|
||||||
| Service Lock | Petstore backend unit + Petstore 专用 Nginx server blocks + Petstore static roots |
|
| Service Lock | Petstore backend unit + Petstore 专用 Nginx server blocks + Petstore static roots |
|
||||||
| Depends On | 冻结 RC、真实域名/TLS、备份、八个迁移、微信合法域名 |
|
| Depends On | 冻结 RC、真实域名/TLS、备份、目标 RC 包含的全部迁移、微信合法域名 |
|
||||||
| Acceptance | 预检、构建、readiness、只读 smoke、三角色人工 smoke、回滚演练均有证据 |
|
| Acceptance | 预检、构建、readiness、只读 smoke、三角色人工 smoke、回滚演练均有证据 |
|
||||||
| RC Included | Yes |
|
| RC Included | Yes |
|
||||||
| Due Date | TBD |
|
| Due Date | TBD |
|
||||||
@ -222,7 +222,7 @@ SMOKE_ALLOWED_ORIGIN=https://<admin-or-report-domain> \
|
|||||||
|
|
||||||
### 9.2 数据库回滚边界
|
### 9.2 数据库回滚边界
|
||||||
|
|
||||||
本批八个迁移以新增列/表/索引和兼容回填为主,旧应用应忽略新增结构。因此常规回滚只回应用,不删除列、表、索引,不执行自动 down migration,也不把已产生的新业务数据覆盖回旧备份。
|
RC1~RC6 冻结的八个迁移以新增列/表/索引和兼容回填为主,旧应用应忽略新增结构。后续 RC 必须把新增迁移一并冻结到 manifest;例如部署包含智能预约会话实体的 backend 前,还必须执行 `20260802_create_booking_agent_session.sql`。因此常规回滚只回应用,不删除列、表、索引,不执行自动 down migration,也不把已产生的新业务数据覆盖回旧备份。
|
||||||
|
|
||||||
只有确认发生灾难性数据破坏、已冻结所有写入、明确接受备份时间点之后的数据丢失,并取得用户/业务负责人、DBA 和隐私责任人的书面授权后,才可执行整库恢复。恢复必须先在隔离库验证,再制定专门变更单;本 Runbook 不授权该操作。
|
只有确认发生灾难性数据破坏、已冻结所有写入、明确接受备份时间点之后的数据丢失,并取得用户/业务负责人、DBA 和隐私责任人的书面授权后,才可执行整库恢复。恢复必须先在隔离库验证,再制定专门变更单;本 Runbook 不授权该操作。
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ SMOKE_ALLOWED_ORIGIN=https://<admin-or-report-domain> \
|
|||||||
|
|
||||||
- 四仓冻结 commit 与产物校验和;
|
- 四仓冻结 commit 与产物校验和;
|
||||||
- 备份及隔离恢复验证;
|
- 备份及隔离恢复验证;
|
||||||
- 八个迁移执行和末尾验证结果;
|
- 目标 RC 包含的全部迁移执行和末尾验证结果;
|
||||||
- 最终配置门禁与后端只读预检;
|
- 最终配置门禁与后端只读预检;
|
||||||
- `nginx -t`、readiness、自动只读 smoke;
|
- `nginx -t`、readiness、自动只读 smoke;
|
||||||
- boss/staff/customer 三角色人工 smoke;
|
- boss/staff/customer 三角色人工 smoke;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user