Files
Home-Care/居家上门服务系统_可执行实现方案_补齐可开工版.md
comclib 4a2eb09606
Some checks failed
CI / backend (push) Has been cancelled
CI / website (push) Has been cancelled
chore: 文档整理 — 移动至 docs/ 目录, 更新 IMPLEMENTATION_PLAN.md
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 11:52:03 +08:00

1968 lines
77 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 居家上门服务系统 — 可执行实现方案(补齐可开工版)
> 生成日期2026-05-15
> 补齐版本V1.1 生产可交付补强版
> 基于V2.0 工程落地增强版 + V2.1 行业经验增强版 + V2.2 边界限制增强版
> 项目状态:全新仓库,从零搭建
> 本版结论可以进入实现但必须按本补齐版执行。本文已补齐幂等表、任务执行日志、Outbox 并发安全、delivery 最小闭环、支付退款、异常监管、完整 OpenAPI 契约、E2E/并发/失败注入测试、灰度回滚与上线验收门槛。
---
## 0. 补齐版执行口径
本补齐版用于替代原执行方案中不完整或容易产生歧义的部分。若本文后续章节与原章节存在冲突,以本补齐版中的以下规则为准:
1. **delivery 最小闭环必须进入 MVP 第一批**,不能整体后移。
2. **幂等不能只依赖 Redis 或状态流转表**,必须新增 `hss_idempotency_records`
3. **定时任务必须有执行日志**,必须新增 `hss_job_execution_logs`
4. **Outbox 必须具备并发抢占、重试、死信能力**,不能只做简单轮询。
5. **支付、退款、冲正必须独立建模**,不能只放在结算表字段里。
6. **异常处理、监管整改、投诉反馈必须独立闭环**,不能只在工单备注里处理。
7. **状态机必须拆为规则判断与动作编排两层**,不能只返回目标状态。
8. **OpenAPI 契约必须覆盖消费者端、管理端、delivery 端和内部任务接口**
9. **测试必须覆盖并发、重复提交、Outbox 失败、支付重复回调、任务重跑、弱网补传**
10. **上线采用 roll-forward + feature flag + dry-run + shadow 模式**,不能依赖直接删字段或强回滚。
---
## 1. 需求与约束摘要
| 项 | 内容 |
|---|---|
| **任务类型** | 新接口 / 新能力开发(全新系统) |
| **目标** | 实现居家上门服务全链路闭环系统:需求受理 → 评估定级 → 方案制定 → 派单调度 → 上门执行 → 过程监管 → 验收反馈 → 结算归档 |
| **硬边界** | Spring Boot / Java 17+、PostgreSQL、Redis、MQTT(通知)、对象存储(文件)、RESTful+action、OpenAPI 3.1、hss_表前缀、Outbox通知、四层状态机、幂等写、前端只传动作不传状态、敏感数据授权脱敏审计 |
| **范围** | 全部模块 + delivery 端小程序 |
---
## 2. 代码依据
本项目为全新仓库,无现有后端代码。以下为架构文档依据:
| 依据文件 | 路径 | 职责 |
|---|---|---|
| V2.0 工程落地增强版 | `docs/ architecture/居家上门服务闭环流程文档_V2工程落地增强版.md` | 业务闭环流程、四层状态机、数据模型、调度算法、通知设计、合规安全、结算对账 |
| V2.1 行业经验增强版 | `docs/ architecture/居家上门服务闭环流程文档_V2.1_行业经验增强版.md` | 美团三层调度、ETA预测、VRPTW建模、delivery智能助手、运力运营中心、主数据平台、SRE稳定性 |
| V2.2 边界限制增强版 | `/home/akoo/居家服务/居家上门服务闭环流程文档_V2.2_边界限制增强版.md` | 12条硬约束、技术栈锁定、DDL边界、接口风格、部署环境、协作边界 |
---
## 3. DDL 依据
当前仓库无 `db/init.sql``db/update.sql`。以下设计基于 V2.0 文档 4.1 节数据域划分(第 939-958 行),结合 V2.2 第 16.3 节 DDL 边界约束。
| 数据域 | 设计表名hss_前缀 | 来源 |
|---|---|---|
| 申请域 | `hss_service_applications` | V2.0 §4.1 |
| 用户画像域 | `hss_patient_profiles` | V2.0 §4.1 |
| 评估域 | `hss_assessment_tasks``hss_assessment_reports` | V2.0 §4.1 |
| 异议域 | `hss_objections` | V2.0 §4.2 |
| 方案域 | `hss_service_plans``hss_service_plan_items``hss_plan_versions` | V2.0 §4.1 |
| 计划域 | `hss_service_schedules` | V2.0 §4.1 |
| 工单域 | `hss_work_orders``hss_work_order_items` | V2.0 §4.1 |
| 执行域 | `hss_checkins``hss_execution_records``hss_evidence_files` | V2.0 §4.1 |
| 异常域 | `hss_exceptions``hss_exception_actions` | V2.0 §4.1 |
| 监管域 | `hss_spot_checks``hss_violations``hss_corrections` | V2.0 §4.1 |
| 验收域 | `hss_acceptances``hss_complaints` | V2.0 §4.1 |
| 结算域 | `hss_settlements``hss_settlement_items``hss_payments``hss_refunds` | V2.0 §4.1 |
| 归档域 | `hss_ledgers``hss_archive_files` | V2.0 §4.1 |
| 通知域 | `hss_notification_outbox``hss_notification_receipts` | V2.0 §7.2 |
| 审计域 | `hss_audit_logs``hss_state_transitions` | V2.0 §3.6、§8.4 |
| 合规域 | `hss_consent_records``hss_data_access_logs` | V2.0 §8.2 |
| 调度域V2.1扩展) | `hss_service_grids``hss_grid_capacity_daily``hss_staff_skill_capacity``hss_capacity_forecasts``hss_capacity_alerts` | V2.1 §15.2.1 |
| 主数据域V2.1扩展) | `hss_md_orgs``hss_md_staff``hss_md_qualifications``hss_md_service_items``hss_md_regions``hss_md_price_rules` | V2.1 §15.7 |
---
## 4. 改动范围清单
全部为新增文件。
| 路径 | 增/删/改 | 摘要 |
|---|---|---|
| `pom.xml` | 增 | Maven 构建配置Spring Boot 3.x + Java 17 |
| `src/main/java/com/meizhou/hss/` | 增 | 根包目录 |
| `src/main/java/.../common/` | 增 | 公共模块:响应体、异常、工具类、幂等注解、审计切面 |
| `src/main/java/.../config/` | 增 | Spring 配置Security、Redis、MQTT、对象存储、定时任务、OpenAPI |
| `src/main/java/.../statemachine/` | 增 | 四层状态机引擎:申请、方案、工单、结算 |
| `src/main/java/.../module/application/` | 增 | 申请域controller/service/repository/entity/dto |
| `src/main/java/.../module/assessment/` | 增 | 评估域controller/service/repository/entity/dto |
| `src/main/java/.../module/plan/` | 增 | 方案域controller/service/repository/entity/dto |
| `src/main/java/.../module/schedule/` | 增 | 计划与调度域 |
| `src/main/java/.../module/workorder/` | 增 | 工单域 |
| `src/main/java/.../module/execution/` | 增 | 执行域:签到、执行记录、证据链 |
| `src/main/java/.../module/exception/` | 增 | 异常域:异常上报与处理 |
| `src/main/java/.../module/supervision/` | 增 | 监管域:抽查、违规、整改 |
| `src/main/java/.../module/acceptance/` | 增 | 验收域:验收、评价、投诉 |
| `src/main/java/.../module/settlement/` | 增 | 结算域:结算、支付、退款 |
| `src/main/java/.../module/archive/` | 增 | 归档域:台账、归档文件 |
| `src/main/java/.../module/notification/` | 增 | 通知域Outbox 与回执 |
| `src/main/java/.../module/audit/` | 增 | 审计域:审计日志、状态流转 |
| `src/main/java/.../module/compliance/` | 增 | 合规域:授权同意、数据访问日志 |
| `src/main/java/.../module/masterdata/` | 增 | 主数据域:机构、人员、资质、服务项目、区域、价格 |
| `src/main/java/.../module/capacity/` | 增 | 运力域:服务网格、容量、预测 |
| `src/main/resources/db/migration/` | 增 | Flyway 迁移脚本 |
| `src/main/resources/application.yml` | 增 | 主配置 |
| `src/test/java/.../` | 增 | 单元测试与集成测试 |
| `delivery-miniapp/` | 增 | delivery 端小程序uni-app |
---
## 5. 方案概述
### 5.1 分层架构
```
┌──────────────────────────────────────────────┐
│ Controller 层REST + action-style REST
│ - 参数校验Spring Validation
│ - 幂等拦截Idempotency-Key
│ - 权限注解(@PreAuthorize
│ - OpenAPI 注解SpringDoc
└──────────────────┬───────────────────────────┘
┌──────────────────▼───────────────────────────┐
│ Service 层(业务编排) │
│ - 状态机调用(不跳过状态检查) │
│ - 事务边界(@Transactional
│ - Outbox 写入(同事务) │
│ - 审计日志写入 │
└──────────────────┬───────────────────────────┘
┌──────────────────▼───────────────────────────┐
│ Repository 层(数据访问) │
│ - MyBatis-Plus BaseMapper │
│ - 自定义 SQL复杂查询/统计) │
│ - 乐观锁 version 字段 │
└──────────────────┬───────────────────────────┘
┌──────────────────▼───────────────────────────┐
│ Domain 层(领域对象) │
│ - Entity映射表
│ - DTO / VO / Request / Response │
│ - 状态枚举 │
│ - 业务异常 │
└──────────────────────────────────────────────┘
```
### 5.2 核心数据流
```text
POST /applications → 创建申请DRAFT
POST /applications/{id}/submit → 提交申请PENDING_ACCEPTANCE
POST /applications/{id}/accept → 受理通过PENDING_ASSESSMENT
POST /assessments/{id}/assign → 派发评估ASSESSING
POST /assessments/{id}/submit → 提交评估ASSESSMENT_PASSED
POST /plans → 创建方案PLAN_DRAFT
POST /plans/{id}/submit → 提交签署PLAN_PENDING_SIGN
POST /plans/{id}/sign → 签署通过PLAN_EFFECTIVE
POST /schedules/{id}/generate → 生成服务计划
POST /work-orders/{id}/dispatch → 派单ORDER_ASSIGNED
POST /work-orders/{id}/accept → 接单ORDER_ACCEPTED
POST /work-orders/{id}/check-in → 签到ORDER_CHECKED_IN
POST /work-orders/{id}/start → 开始服务ORDER_IN_SERVICE
POST /execution-records → 逐项记录执行
POST /work-orders/{id}/finish → 完成服务ORDER_COMPLETED
POST /acceptances → 发起验收ACCEPTANCE_PENDING
POST /acceptances/{id}/confirm → 验收通过ACCEPTED
POST /settlements/{id}/generate → 生成结算单
POST /settlements/{id}/approve → 审核通过
POST /settlements/{id}/pay → 支付完成SETTLEMENT_PAID
POST /settlements/{id}/archive → 归档ARCHIVED
```
### 5.3 异常流
```text
任何非终态 → POST /{entity}/{id}/cancel → CANCELLED需原因
评估中 → POST /assessments/{id}/object → REVIEWING → 维持/重评
方案待签署 → POST /plans/{id}/reject → PLAN_REJECTED → 重新编制
工单已派单 → POST /work-orders/{id}/reassign → 改派
工单服务中 → POST /work-orders/{id}/report-exception → ORDER_EXCEPTION → 协调/改派/关闭
验收拒绝 → POST /acceptances/{id}/reject → 创建问题处理单
结算不通过 → POST /settlements/{id}/return → 退回修改
```
---
## 6. 代码级修改说明(核心)
### 6.1 项目初始化
**文件**`pom.xml`(新增)
当前逻辑:不存在。
拟议改动:创建 Maven 父 POM管理所有模块依赖。
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
</parent>
<groupId>com.meizhou</groupId>
<artifactId>hss-home-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>HSS Home Service</name>
<properties>
<java.version>17</java.version>
<mybatis-plus.version>3.5.6</mybatis-plus.version>
<springdoc.version>2.5.0</springdoc.version>
<flyway.version>10.11.0</flyway.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
```
### 6.2 公共模块
**目录**`src/main/java/com/meizhou/hss/common/`(新增)
#### 6.2.1 统一响应体
**文件**`ApiResponse.java`(新增)
当前逻辑:不存在。
拟议改动:所有接口统一使用此响应格式。
```java
// 新增
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse<T> {
private int code; // 200 成功
private String message;
private T data;
private String requestId; // UUID
private long timestamp; // System.currentTimeMillis()
public static <T> ApiResponse<T> ok(T data) { ... }
public static <T> ApiResponse<T> fail(int code, String message) { ... }
}
```
#### 6.2.2 幂等拦截
**文件**`@Idempotent.java` + `IdempotentAspect.java`(新增)
当前逻辑:不存在。
拟议改动:基于 Redis 实现 request_id 幂等。相同 `requestId + action + entityId` 在 TTL 内重复提交返回首次结果。
```java
// 新增注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
String prefix() default "idempotent";
long ttlSeconds() default 300;
}
// 新增切面
@Aspect
@Component
public class IdempotentAspect {
@Around("@annotation(idempotent)")
public Object around(ProceedingJoinPoint pjp, Idempotent idempotent) {
// 从请求头获取 Idempotency-Key
// 拼接 key = prefix + ":" + idempotencyKey
// Redis SET NX EX成功则执行失败则返回缓存结果
}
}
```
#### 6.2.3 审计字段基类
**文件**`BaseEntity.java`(新增)
```java
// 新增 - 所有 hss_ 表 Entity 继承此类
@Data
public abstract class BaseEntity {
@TableId(type = IdType.AUTO)
private Long id;
private Long tenantId;
private Long orgId;
private String status;
private Integer version;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private Long createdBy;
private Long updatedBy;
@TableLogic
private Integer deleted; // 0 正常, 1 已删除
}
```
### 6.3 状态机引擎
**目录**`src/main/java/com/meizhou/hss/statemachine/`(新增)
#### 文件清单
| 文件 | 职责 |
|---|---|
| `StateMachine.java` | 通用状态机接口:`transition(entity, action, context) → targetState` |
| `StateMachineConfig.java` | 状态转换规则配置(从 YAML/DB 加载) |
| `TransitionRule.java` | 单条转换规则fromStatus + action + role → toStatus + constraints |
| `ApplicationStateMachine.java` | 申请状态机实现 |
| `PlanStateMachine.java` | 方案状态机实现 |
| `WorkOrderStateMachine.java` | 工单状态机实现 |
| `SettlementStateMachine.java` | 结算状态机实现 |
| `StateTransitionException.java` | 非法状态转换异常 |
**当前逻辑**:不存在。
**拟议改动**:基于 V2.0 文档 §3.2~3.5 的状态转换表实现。
```java
// 新增 - TransitionRule
public record TransitionRule(
String entityType, // application / plan / work_order / settlement
String fromStatus,
String action, // submit / accept / reject / check-in / finish / approve / ...
String requiredRole, // 允许执行此动作的角色
String toStatus,
List<String> constraints // 约束条件:如 "hasAssessmentReport"、"amountMatched"
) {}
// 新增 - StateMachine 核心方法
public class StateMachine {
// 校验转换是否合法
public boolean canTransition(String entityType, String fromStatus,
String action, String role);
// 执行转换(不通过抛 StateTransitionException
public String transition(String entityType, String fromStatus,
String action, String role, Map<String, Object> context);
// 记录状态流转到 hss_state_transitions
private void recordTransition(...);
}
```
状态转换规则初始化(基于文档 §3.2~3.5,部分示例):
```java
// 新增 - 申请状态机规则
rules.add(new TransitionRule("application", "DRAFT", "submit", "APPLICANT",
"PENDING_ACCEPTANCE", List.of("materialsComplete")));
rules.add(new TransitionRule("application", "PENDING_ACCEPTANCE", "accept", "RECEPTIONIST",
"PENDING_ASSESSMENT", List.of("ageCheck", "qualificationCheck", "duplicateCheck")));
rules.add(new TransitionRule("application", "PENDING_ACCEPTANCE", "return", "RECEPTIONIST",
"RETURNED", List.of("returnReasonRequired")));
// ... 等全部规则
```
### 6.4 申请域模块
**目录**`src/main/java/com/meizhou/hss/module/application/`
#### 文件清单
| 文件 | 职责 |
|---|---|
| `entity/ServiceApplicationEntity.java` | 映射 `hss_service_applications` |
| `dto/ApplicationCreateRequest.java` | 创建申请请求 DTO |
| `dto/ApplicationSubmitRequest.java` | 提交申请请求 DTO |
| `dto/ApplicationResponse.java` | 申请响应 DTO |
| `dto/ApplicationListQuery.java` | 列表查询参数 |
| `repository/ServiceApplicationMapper.java` | MyBatis-Plus Mapper |
| `service/ApplicationService.java` | 业务逻辑 |
| `service/ApplicationValidationService.java` | 自动校验(材料完整性、资格、重复申请) |
| `controller/ApplicationController.java` | REST 接口 |
**当前逻辑**:不存在。
**拟议改动**
`ApplicationController.java`
```java
// 新增
@RestController
@RequestMapping("/api/hss/applications")
@Tag(name = "服务申请")
public class ApplicationController {
@PostMapping
@Idempotent(prefix = "app:create")
public ApiResponse<ApplicationResponse> create(
@Valid @RequestBody ApplicationCreateRequest req) {
// Service: 校验 → 创建 DRAFT 状态申请 → 记录状态流转
}
@PostMapping("/{id}/submit")
@Idempotent(prefix = "app:submit")
public ApiResponse<ApplicationResponse> submit(
@PathVariable Long id, @Valid @RequestBody ApplicationSubmitRequest req) {
// Service: 状态机 DRAFT→PENDING_ACCEPTANCE → 写 Outbox 通知受理员
}
@PostMapping("/{id}/accept")
@Idempotent(prefix = "app:accept")
@PreAuthorize("hasRole('RECEPTIONIST')")
public ApiResponse<ApplicationResponse> accept(@PathVariable Long id) {
// Service: 校验(材料+资格+重复)→ 状态机 PENDING_ACCEPTANCE→PENDING_ASSESSMENT
}
@PostMapping("/{id}/return")
@Idempotent(prefix = "app:return")
@PreAuthorize("hasRole('RECEPTIONIST')")
public ApiResponse<ApplicationResponse> returnApplication(
@PathVariable Long id, @Valid @RequestBody ReturnRequest req) {
// 约束:必须填写退回原因
}
@PostMapping("/{id}/cancel")
@Idempotent(prefix = "app:cancel")
public ApiResponse<ApplicationResponse> cancel(@PathVariable Long id) {
// 约束:申请人本人或授权家属
}
@GetMapping
public ApiResponse<Page<ApplicationResponse>> list(ApplicationListQuery query) {
// 数据范围:按 tenant_id、org_id、角色过滤
}
@GetMapping("/{id}")
public ApiResponse<ApplicationResponse> getById(@PathVariable Long id) {
// 脱敏:非授权角色隐藏完整地址、电话
}
}
```
**注**:其余模块(评估、方案、调度、工单、执行、异常、监管、验收、结算、归档、通知、审计、合规、主数据、运力)的代码结构遵循相同模式,此处为避免文档过度膨胀,仅输出申请域作为样板。完整代码在实施阶段逐模块编写。
### 6.5 通知 Outbox 模块
**目录**`src/main/java/com/meizhou/hss/module/notification/`
关键设计:
```java
// 新增 - 通知创建(在业务事务内调用)
@Service
public class NotificationService {
// 与业务在同一事务中写入 Outbox
@Transactional
public void createNotification(Long entityId, String entityType,
String channel, String template, Map<String, Object> params) {
NotificationOutboxEntity outbox = new NotificationOutboxEntity();
outbox.setEntityId(entityId);
outbox.setChannel(channel); // MQTT / WECHAT / SMS
outbox.setStatus("CREATED");
outbox.setRequestId(IdempotencyContext.getRequestId());
outboxMapper.insert(outbox);
}
}
// 新增 - 定时任务:扫描 Outbox 并异步发送
@Component
public class NotificationSender {
@Scheduled(fixedDelay = 2000) // 每2秒扫描
public void sendPending() {
// SELECT * FROM hss_notification_outbox WHERE status='CREATED' LIMIT 100
// 发送 → 更新 status=SENT → 记录 receipt
// 失败 → status=FAILED, retry_count+1
}
}
```
### 6.6 审计模块
**目录**`src/main/java/com/meizhou/hss/module/audit/`
```java
// 新增 - AOP 切面自动记录审计
@Aspect
@Component
public class AuditAspect {
@Around("@annotation(auditable)")
public Object around(ProceedingJoinPoint pjp, Auditable auditable) {
// 记录操作人、时间、IP、设备、操作类型、业务对象ID、前后值
}
}
// 新增 - 状态流转记录(状态机内部调用)
// 写入 hss_state_transitions
// entity_type, entity_id, from_status, action, to_status,
// operator_id, operator_role, reason, request_id, created_at
```
### 6.7 调度算法模块
**目录**`src/main/java/com/meizhou/hss/module/schedule/algorithm/`
```java
// 新增 - 两阶段调度
@Service
public class DispatchAlgorithm {
// 阶段1硬约束过滤
public List<StaffCandidate> hardFilter(List<Staff> allStaff, WorkOrder order) {
return allStaff.stream()
.filter(s -> s.getStatus() == StaffStatus.ACTIVE)
.filter(s -> s.hasQualification(order.getRequiredSkills()))
.filter(s -> s.getRegion().contains(order.getServiceAddress().getRegion()))
.filter(s -> !hasTimeConflict(s, order))
.filter(s -> !s.isBlacklisted())
.filter(s -> s.getTodayOrderCount() < s.getMaxDailyOrders())
.toList();
}
// 阶段2软约束评分
public List<ScoredStaff> scoreAndRank(List<StaffCandidate> candidates, WorkOrder order) {
// score = distance * 0.25 + skill * 0.25 + workload * 0.20
// + rating * 0.15 + response * 0.10 + familiarity * 0.05
// 返回 Top5附解释
}
}
```
---
## 7. 接口设计方案(任务类型=1 强制)
### 7.1 核心接口清单
按主链路阶段组织,以下为核心接口设计。
#### 7.1.1 服务申请接口组
**接口1创建服务申请**
| 接口名称 | 创建服务申请 |
| -------- | ------------------------------------------------------ |
| 接口地址 | `/api/hss/applications` |
| 请求方式 | `POST` |
| 接口描述 | 服务对象/家属提交服务申请,创建后状态为 DRAFT |
| 参数名 | 类型 | 是否必填 | 说明 |
| ----------- | ------ | -------- | --------------------------- |
| patientId | string | 是 | 服务对象ID |
| serviceType | string | 是 | 服务类型枚举HOME_CARE / REHABILITATION / BATH_ASSIST / ASSESSMENT |
| channel | string | 是 | 申请渠道APP / WECHAT / PHONE / COMMUNITY / HOSPITAL |
| contactName | string | 是 | 联系人姓名 |
| contactPhone | string | 是 | 联系人电话 |
| address | string | 是 | 服务地址 |
| regionCode | string | 是 | 区域编码 |
| notes | string | 否 | 备注说明 |
| attachmentIds | array | 否 | 附件ID列表 |
| 字段路径 | 类型 | 示例 | 说明 |
| -------- | ------- | -------------- | -------------------- |
| code | int | 200 | 状态码 |
| success | boolean | true | 是否成功 |
| message | string | 申请创建成功 | 响应消息 |
| data.id | string | 1001 | 申请ID |
| data.status | string | DRAFT | 申请状态 |
| data.createdAt | string | 2026-05-15T10:30:00 | 创建时间 |
请求示例:
```json
{
"patientId": "2001",
"serviceType": "HOME_CARE",
"channel": "WECHAT",
"contactName": "张三",
"contactPhone": "138****5678",
"address": "梅江区金山街道XX小区3栋201",
"regionCode": "441402001",
"notes": "老人独居,需要日常护理",
"attachmentIds": ["att_001", "att_002"]
}
```
返回示例:
```json
{
"code": 200,
"message": "申请创建成功",
"data": {
"id": "1001",
"status": "DRAFT",
"createdAt": "2026-05-15T10:30:00"
},
"requestId": "req-uuid-abc123",
"timestamp": 1715747400000
}
```
---
**接口2提交服务申请**
| 接口名称 | 提交服务申请 |
| -------- | ------------------------------------------------------ |
| 接口地址 | `/api/hss/applications/{id}/submit` |
| 请求方式 | `POST` |
| 接口描述 | 将草稿状态申请提交为待受理,触发自动校验 |
| 参数名 | 类型 | 是否必填 | 说明 |
| ----------- | ------ | -------- | --------------------------- |
| id | string | 是 | 路径参数申请ID |
| 字段路径 | 类型 | 示例 | 说明 |
| -------- | ------- | -------------- | -------------------- |
| code | int | 200 | 状态码 |
| data.status | string | PENDING_ACCEPTANCE | 新状态 |
| data.validationResult.passed | boolean | true | 自动校验结果 |
---
**接口3受理通过**
| 接口名称 | 受理通过 |
| -------- | ------------------------------------------------------ |
| 接口地址 | `/api/hss/applications/{id}/accept` |
| 请求方式 | `POST` |
| 接口描述 | 受理员审核通过,申请进入待评估状态 |
| 参数名 | 类型 | 是否必填 | 说明 |
| ----------- | ------ | -------- | --------------------------- |
| id | string | 是 | 路径参数申请ID |
| reason | string | 否 | 审核备注 |
---
**接口4受理退回**
| 接口名称 | 受理退回 |
| -------- | ------------------------------------------------------ |
| 接口地址 | `/api/hss/applications/{id}/return` |
| 请求方式 | `POST` |
| 接口描述 | 受理员退回申请,需填写退回原因 |
| 参数名 | 类型 | 是否必填 | 说明 |
| ----------- | ------ | -------- | --------------------------- |
| id | string | 是 | 路径参数 |
| reason | string | 是 | 退回原因(必填) |
---
#### 7.1.2 工单执行接口组
**接口5GPS 签到**
| 接口名称 | GPS签到 |
| -------- | ------------------------------------------------------ |
| 接口地址 | `/api/hss/work-orders/{id}/check-in` |
| 请求方式 | `POST` |
| 接口描述 | 服务人员在服务地址200米内签到需GPS+照片+对象确认 |
| 参数名 | 类型 | 是否必填 | 说明 |
| ----------- | ------ | -------- | --------------------------- |
| id | string | 是 | 工单ID |
| latitude | number | 是 | 纬度 |
| longitude | number | 是 | 经度 |
| photoFileId | string | 是 | 现场照片文件ID |
| patientConfirmed | boolean | 是 | 服务对象是否确认 |
| patientSignatureId | string | 否 | 对象签名文件ID |
| 字段路径 | 类型 | 示例 | 说明 |
| -------- | ------- | -------------- | -------------------- |
| code | int | 200 | 状态码 |
| data.status | string | ORDER_CHECKED_IN | 新状态 |
| data.distance | number | 85.5 | 签到位置距服务地址距离(米) |
| data.checkinTime | string | 2026-05-15T09:05:00 | 签到时间 |
请求示例:
```json
{
"latitude": 24.2878,
"longitude": 116.1271,
"photoFileId": "file_checkin_001",
"patientConfirmed": true,
"patientSignatureId": "sig_001"
}
```
返回示例:
```json
{
"code": 200,
"message": "签到成功",
"data": {
"id": "5001",
"status": "ORDER_CHECKED_IN",
"distance": 85.5,
"checkinTime": "2026-05-15T09:05:00"
},
"requestId": "req-uuid-def456",
"timestamp": 1715747700000
}
```
---
**接口6服务完成提交**
| 接口名称 | 服务完成提交 |
| -------- | ------------------------------------------------------ |
| 接口地址 | `/api/hss/work-orders/{id}/finish` |
| 请求方式 | `POST` |
| 接口描述 | 服务人员完成所有必做项目后提交,工单进入已完成状态 |
| 参数名 | 类型 | 是否必填 | 说明 |
| ----------- | ------ | -------- | --------------------------- |
| id | string | 是 | 工单ID |
| executionRecords | array | 是 | 项目执行记录列表 |
| executionRecords[].planItemId | string | 是 | 方案项目ID |
| executionRecords[].status | string | 是 | COMPLETED / PARTIAL / NOT_COMPLETED / SKIPPED / USER_REFUSED |
| executionRecords[].actualStartTime | string | 是 | 实际开始时间 |
| executionRecords[].actualEndTime | string | 是 | 实际结束时间 |
| executionRecords[].evidenceFileIds | array | 否 | 证据文件ID列表 |
| executionRecords[].notes | string | 否 | 执行备注 |
| signOffLatitude | number | 是 | 签退纬度 |
| signOffLongitude | number | 是 | 签退经度 |
| serviceSummary | string | 否 | 服务总结 |
---
#### 7.1.3 结算接口组
**接口7生成结算单**
| 接口名称 | 生成结算单 |
| -------- | ------------------------------------------------------ |
| 接口地址 | `/api/hss/settlements/generate` |
| 请求方式 | `POST` |
| 接口描述 | 基于已验收工单生成结算单,自动汇总金额与抵扣 |
| 参数名 | 类型 | 是否必填 | 说明 |
| ----------- | ------ | -------- | --------------------------- |
| workOrderIds | array | 是 | 已验收工单ID列表 |
| periodStart | string | 是 | 结算周期开始日期 |
| periodEnd | string | 是 | 结算周期结束日期 |
| 字段路径 | 类型 | 示例 | 说明 |
| -------- | ------- | -------------- | -------------------- |
| data.id | string | 7001 | 结算单ID |
| data.totalAmount | number | 1200.00 | 总金额 |
| data.insuranceDeduction | number | 800.00 | 长护险抵扣 |
| data.selfPayAmount | number | 400.00 | 自费金额 |
| data.items | array | [...] | 结算明细 |
---
### 7.2 接口契约约定
- 所有写接口必须带 `Idempotency-Key` 请求头
- 所有分页接口参数:`page`默认1`size`默认20最大100`sort`(如 `createdAt,desc`
- 状态动作接口路径格式:`POST /api/hss/{resource}/{id}/{action}`
- 资源 CRUD`GET/POST/PUT/DELETE /api/hss/{resource}``/{id}`
- 统一错误响应:
```json
{
"code": 40001,
"message": "参数校验失败",
"details": [
{"field": "contactPhone", "message": "联系电话格式不正确"}
],
"requestId": "req-uuid-err123"
}
```
### 7.3 错误码规划
| 错误码范围 | 含义 |
|---|---|
| 200 | 成功 |
| 40001-40099 | 参数校验错误 |
| 40101-40199 | 认证/授权错误 |
| 40301-40399 | 权限不足 |
| 40401-40499 | 资源不存在 |
| 40901-40999 | 状态冲突(非法状态转换) |
| 40910-40919 | 幂等冲突(重复提交) |
| 42201-42299 | 业务规则校验失败 |
| 50001-50099 | 服务器内部错误 |
| 50301-50399 | 依赖服务不可用 |
---
## 8. 数据库与迁移计划
### 8.1 DDL 变更明细
迁移脚本位于 `src/main/resources/db/migration/`,采用 Flyway 管理。
#### V1__baseline.sql初始基线
核心表结构(部分示例):
```sql
-- ==========================================
-- 基线迁移 V1创建居家服务核心业务表
-- ==========================================
-- 1. 申请域
CREATE TABLE hss_service_applications (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
org_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
service_type VARCHAR(32) NOT NULL, -- HOME_CARE / REHABILITATION / BATH_ASSIST / ASSESSMENT
channel VARCHAR(32) NOT NULL, -- APP / WECHAT / PHONE / COMMUNITY / HOSPITAL
contact_name VARCHAR(64) NOT NULL,
contact_phone VARCHAR(20) NOT NULL,
address TEXT NOT NULL,
region_code VARCHAR(20) NOT NULL,
status VARCHAR(32) NOT NULL DEFAULT 'DRAFT',
notes TEXT,
version INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT,
updated_by BIGINT,
deleted SMALLINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_hss_app_status ON hss_service_applications(status);
CREATE INDEX idx_hss_app_patient ON hss_service_applications(patient_id);
CREATE INDEX idx_hss_app_created ON hss_service_applications(created_at);
-- 2. 评估域
CREATE TABLE hss_assessment_tasks (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
org_id BIGINT NOT NULL,
application_id BIGINT NOT NULL REFERENCES hss_service_applications(id),
assessor_id BIGINT,
status VARCHAR(32) NOT NULL DEFAULT 'PENDING_ASSIGNMENT',
-- 评估结果快照
care_level VARCHAR(16), -- LEVEL_1 ~ LEVEL_5
risk_level VARCHAR(16), -- LOW / MEDIUM / HIGH / CRITICAL
report_content JSONB,
version INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT,
updated_by BIGINT,
deleted SMALLINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_hss_at_status ON hss_assessment_tasks(status);
CREATE INDEX idx_hss_at_app ON hss_assessment_tasks(application_id);
CREATE INDEX idx_hss_at_assessor ON hss_assessment_tasks(assessor_id);
CREATE TABLE hss_assessment_reports (
id BIGSERIAL PRIMARY KEY,
task_id BIGINT NOT NULL REFERENCES hss_assessment_tasks(id),
version INTEGER NOT NULL DEFAULT 1,
content JSONB NOT NULL, -- 评估指标详情
conclusion TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT
);
-- 3. 方案域
CREATE TABLE hss_service_plans (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
org_id BIGINT NOT NULL,
application_id BIGINT NOT NULL,
assessment_task_id BIGINT NOT NULL,
status VARCHAR(32) NOT NULL DEFAULT 'PLAN_DRAFT',
version_number INTEGER NOT NULL DEFAULT 1,
total_amount DECIMAL(12,2), -- 方案总金额
insurance_deduction DECIMAL(12,2), -- 长护险抵扣
self_pay_amount DECIMAL(12,2), -- 自费金额
signed_at TIMESTAMP,
signed_by BIGINT,
effective_at TIMESTAMP,
terminated_at TIMESTAMP,
version INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT,
updated_by BIGINT,
deleted SMALLINT NOT NULL DEFAULT 0
);
CREATE TABLE hss_service_plan_items (
id BIGSERIAL PRIMARY KEY,
plan_id BIGINT NOT NULL REFERENCES hss_service_plans(id),
service_item_id BIGINT NOT NULL, -- 引用主数据服务项目
item_name VARCHAR(128) NOT NULL, -- 版本化快照
unit_price DECIMAL(10,2) NOT NULL, -- 版本化快照
frequency INTEGER NOT NULL, -- 服务频次
standard_duration INTEGER, -- 标准服务时长(分钟)
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE hss_plan_versions (
id BIGSERIAL PRIMARY KEY,
plan_id BIGINT NOT NULL,
version_number INTEGER NOT NULL,
snapshot_data JSONB NOT NULL, -- 完整方案快照
change_reason TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT
);
-- 4. 服务计划域
CREATE TABLE hss_service_schedules (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
plan_id BIGINT NOT NULL REFERENCES hss_service_plans(id),
scheduled_date DATE NOT NULL,
time_window_start TIME, -- 预约时间窗开始
time_window_end TIME, -- 预约时间窗结束
status VARCHAR(32) NOT NULL DEFAULT 'SCHEDULED',
version INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_hss_ss_date ON hss_service_schedules(scheduled_date);
CREATE INDEX idx_hss_ss_plan ON hss_service_schedules(plan_id);
-- 5. 工单域
CREATE TABLE hss_work_orders (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
org_id BIGINT NOT NULL,
schedule_id BIGINT REFERENCES hss_service_schedules(id),
plan_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
staff_id BIGINT,
status VARCHAR(32) NOT NULL DEFAULT 'ORDER_CREATED',
service_date DATE NOT NULL,
scheduled_start TIME,
scheduled_end TIME,
risk_level VARCHAR(16),
is_high_risk BOOLEAN DEFAULT FALSE,
version INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT,
updated_by BIGINT,
deleted SMALLINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_hss_wo_status ON hss_work_orders(status);
CREATE INDEX idx_hss_wo_staff ON hss_work_orders(staff_id);
CREATE INDEX idx_hss_wo_date ON hss_work_orders(service_date);
CREATE INDEX idx_hss_wo_patient ON hss_work_orders(patient_id);
CREATE TABLE hss_work_order_items (
id BIGSERIAL PRIMARY KEY,
work_order_id BIGINT NOT NULL REFERENCES hss_work_orders(id),
plan_item_id BIGINT NOT NULL,
item_name VARCHAR(128) NOT NULL,
unit_price DECIMAL(10,2) NOT NULL,
required BOOLEAN DEFAULT TRUE, -- 是否必做
status VARCHAR(32) DEFAULT 'PENDING', -- COMPLETED/PARTIAL/NOT_COMPLETED/SKIPPED/USER_REFUSED
evidence_required BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 6. 执行域
CREATE TABLE hss_checkins (
id BIGSERIAL PRIMARY KEY,
work_order_id BIGINT NOT NULL REFERENCES hss_work_orders(id),
checkin_type VARCHAR(16) NOT NULL, -- CHECKIN / CHECKOUT
latitude DECIMAL(10,7) NOT NULL,
longitude DECIMAL(10,7) NOT NULL,
distance_meters INTEGER, -- 距目标地址距离
photo_file_id VARCHAR(64),
patient_confirmed BOOLEAN,
patient_signature_id VARCHAR(64),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT
);
CREATE TABLE hss_execution_records (
id BIGSERIAL PRIMARY KEY,
work_order_id BIGINT NOT NULL,
work_order_item_id BIGINT NOT NULL,
status VARCHAR(32) NOT NULL, -- COMPLETED/PARTIAL/NOT_COMPLETED/SKIPPED/USER_REFUSED
actual_start TIMESTAMP,
actual_end TIMESTAMP,
notes TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT
);
CREATE TABLE hss_evidence_files (
id BIGSERIAL PRIMARY KEY,
entity_type VARCHAR(32) NOT NULL, -- CHECKIN / EXECUTION / EXCEPTION / ACCEPTANCE
entity_id BIGINT NOT NULL,
file_type VARCHAR(16) NOT NULL, -- PHOTO / VIDEO / AUDIO
file_key VARCHAR(256) NOT NULL, -- 对象存储 key
file_size BIGINT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT
);
-- 7. 异常域
CREATE TABLE hss_exceptions (
id BIGSERIAL PRIMARY KEY,
work_order_id BIGINT NOT NULL REFERENCES hss_work_orders(id),
exception_type VARCHAR(32) NOT NULL, -- PATIENT_ABSENT / PATIENT_REFUSE / WRONG_ADDRESS / ...
description TEXT NOT NULL,
evidence_file_ids TEXT, -- JSON 数组
status VARCHAR(32) NOT NULL DEFAULT 'REPORTED',
handled_by BIGINT,
resolution TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT
);
-- 8. 验收域
CREATE TABLE hss_acceptances (
id BIGSERIAL PRIMARY KEY,
work_order_id BIGINT NOT NULL REFERENCES hss_work_orders(id),
status VARCHAR(32) NOT NULL DEFAULT 'ACCEPTANCE_PENDING',
result VARCHAR(16), -- ACCEPTED / REJECTED
rating SMALLINT, -- 1-5 星
tags TEXT, -- JSON 标签数组
comment TEXT,
rejected_reason TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT
);
-- 9. 结算域
CREATE TABLE hss_settlements (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
org_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
status VARCHAR(32) NOT NULL DEFAULT 'SETTLEMENT_READY',
period_start DATE NOT NULL,
period_end DATE NOT NULL,
total_amount DECIMAL(12,2),
insurance_deduction DECIMAL(12,2),
self_pay_amount DECIMAL(12,2),
paid_at TIMESTAMP,
payment_channel VARCHAR(32),
payment_transaction_id VARCHAR(64),
version INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
created_by BIGINT,
updated_by BIGINT,
deleted SMALLINT NOT NULL DEFAULT 0
);
CREATE TABLE hss_settlement_items (
id BIGSERIAL PRIMARY KEY,
settlement_id BIGINT NOT NULL REFERENCES hss_settlements(id),
work_order_id BIGINT NOT NULL,
execution_record_id BIGINT,
item_name VARCHAR(128),
unit_price DECIMAL(10,2),
actual_amount DECIMAL(10,2),
deduction DECIMAL(10,2),
self_pay DECIMAL(10,2),
status VARCHAR(32)
);
-- 10. 通知域
CREATE TABLE hss_notification_outbox (
id BIGSERIAL PRIMARY KEY,
entity_type VARCHAR(32) NOT NULL,
entity_id BIGINT NOT NULL,
channel VARCHAR(16) NOT NULL, -- MQTT / WECHAT / SMS
template_code VARCHAR(64),
params JSONB,
recipient_id BIGINT,
status VARCHAR(16) NOT NULL DEFAULT 'CREATED',
retry_count INTEGER DEFAULT 0,
max_retries INTEGER DEFAULT 3,
next_retry_at TIMESTAMP,
request_id VARCHAR(64),
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_hss_nf_status ON hss_notification_outbox(status, next_retry_at);
CREATE TABLE hss_notification_receipts (
id BIGSERIAL PRIMARY KEY,
outbox_id BIGINT NOT NULL,
status VARCHAR(16) NOT NULL, -- SENT / DELIVERED / READ / CONFIRMED / FAILED / EXPIRED
sent_at TIMESTAMP,
delivered_at TIMESTAMP,
read_at TIMESTAMP,
error_message TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 11. 审计域
CREATE TABLE hss_state_transitions (
id BIGSERIAL PRIMARY KEY,
entity_type VARCHAR(32) NOT NULL, -- application / plan / work_order / settlement
entity_id BIGINT NOT NULL,
from_status VARCHAR(32),
action VARCHAR(32) NOT NULL,
to_status VARCHAR(32) NOT NULL,
operator_id BIGINT,
operator_role VARCHAR(32),
reason TEXT,
request_id VARCHAR(64),
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_hss_st_entity ON hss_state_transitions(entity_type, entity_id);
CREATE INDEX idx_hss_st_request ON hss_state_transitions(request_id);
CREATE TABLE hss_audit_logs (
id BIGSERIAL PRIMARY KEY,
entity_type VARCHAR(32),
entity_id BIGINT,
action VARCHAR(32) NOT NULL,
operator_id BIGINT,
operator_name VARCHAR(64),
operator_role VARCHAR(32),
client_ip VARCHAR(45),
device_info VARCHAR(256),
detail JSONB,
is_sensitive BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_hss_al_entity ON hss_audit_logs(entity_type, entity_id);
CREATE INDEX idx_hss_al_operator ON hss_audit_logs(operator_id);
CREATE INDEX idx_hss_al_time ON hss_audit_logs(created_at);
-- 12. 合规域
CREATE TABLE hss_consent_records (
id BIGSERIAL PRIMARY KEY,
patient_id BIGINT NOT NULL,
consent_type VARCHAR(32) NOT NULL, -- GPS / PHOTO / HEALTH / AUDIO_VIDEO
consent_status VARCHAR(16) NOT NULL, -- GRANTED / REVOKED / EXPIRED
granted_at TIMESTAMP,
revoked_at TIMESTAMP,
expires_at TIMESTAMP,
created_by BIGINT,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE hss_data_access_logs (
id BIGSERIAL PRIMARY KEY,
operator_id BIGINT NOT NULL,
data_type VARCHAR(32) NOT NULL, -- PERSONAL / HEALTH / LOCATION / FINANCIAL
entity_type VARCHAR(32),
entity_id BIGINT,
access_action VARCHAR(16) NOT NULL, -- VIEW / EXPORT / DOWNLOAD
client_ip VARCHAR(45),
reason TEXT,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 唯一约束:幂等键
CREATE UNIQUE INDEX uk_hss_st_request ON hss_state_transitions(request_id, entity_type, entity_id);
```
### 8.2 执行顺序与窗口建议
| 阶段 | 脚本 | 内容 | 建议窗口 |
|---|---|---|---|
| 1 | V1__baseline.sql | 全部核心表创建 | 首次部署(停机窗口 10min |
| 2 | V2__seed_master_data.sql | 主数据初始化(区域、服务项目、资质字典) | 紧随 V1 |
| 3 | V3__add_indexes.sql | 性能索引补充 | 在线CREATE INDEX CONCURRENTLY |
| 后续 | V4+ | 增量变更 | 按需,遵循 flyway 版本号 |
### 8.3 回滚策略
- 每次迁移对应一个 `U` 版本回滚脚本(如 `U1__baseline_rollback.sql`
- 回滚原则:非生产环境可直接 DROP生产环境采用 `migrate down + data restore`
- 关键变更必须备份受影响数据:`CREATE TABLE xxx_backup AS SELECT * FROM xxx WHERE ...`
- 禁止 `DROP COLUMN` 直接执行:先标记废弃 → 观察一个版本 → 再删除
---
## 9. 接口契约与兼容性
### 9.1 兼容性说明
| 方面 | 策略 |
|---|---|
| 账号/登录 | 兼容现有平台 JWT Token 格式 |
| 角色/权限 | 新增居家服务角色(受理员、评估员、方案制定员、调度员、服务人员、监管员、结算员),不影响现有角色 |
| 机构/用户 | 复用现有 org_id / user_id 体系 |
| 文件上传 | 复用现有对象存储接口,居家服务文件单独 folder |
| 业务表 | 全新 `hss_` 前缀,不影响现有业务表 |
### 9.2 版本管理
- API 路径不加版本号,通过 Header `Accept-Version` 管理
- 破坏性变更走新接口 + 旧接口保留一个版本后废弃
---
## 10. 自测与回归
### 10.1 单元测试范围
| 测试对象 | 覆盖内容 |
|---|---|
| 状态机 | 所有合法转换、非法转换拦截、重复提交幂等 |
| 校验服务 | 年龄校验、资格校验、重复申请校验 |
| 调度算法 | 硬约束过滤逻辑、软约束评分计算、Top5排序 |
| 结算计算 | 金额汇总、抵扣计算、部分完成折算 |
### 10.2 集成测试范围
| 测试场景 | 验证点 |
|---|---|
| 主链路 | 申请→评估→方案→工单→执行→验收→结算→归档 全流程 |
| 异常链路 | 退回、异议、拒签、改派、异常上报、拒绝验收、结算退回 |
| 通知链路 | Outbox 写入→定时发送→回执记录 |
| 权限链路 | 角色隔离、数据范围过滤、字段脱敏 |
| 并发场景 | 同 request_id 重复提交、派单并发冲突 |
### 10.3 关键回归场景
- 状态机规则变更后,所有上游调用方不受影响(规则集中管理)
- 结算公式变更后,历史结算单金额不变(版本化快照)
- 服务项目价格调整后,已签署方案不受影响(版本冻结)
---
## 11. 工程目录结构总览
```
hss-home-service/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/com/meizhou/hss/
│ │ │ ├── HssApplication.java # Spring Boot 启动类
│ │ │ ├── common/
│ │ │ │ ├── ApiResponse.java # 统一响应
│ │ │ │ ├── BaseEntity.java # 审计字段基类
│ │ │ │ ├── ErrorCode.java # 错误码枚举
│ │ │ │ ├── BusinessException.java # 业务异常
│ │ │ │ ├── Idempotent.java # 幂等注解
│ │ │ │ ├── IdempotentAspect.java # 幂等切面
│ │ │ │ ├── Auditable.java # 审计注解
│ │ │ │ └── AuditAspect.java # 审计切面
│ │ │ ├── config/
│ │ │ │ ├── SecurityConfig.java
│ │ │ │ ├── RedisConfig.java
│ │ │ │ ├── MqttConfig.java
│ │ │ │ ├── ObjectStorageConfig.java
│ │ │ │ ├── SchedulerConfig.java
│ │ │ │ ├── OpenApiConfig.java
│ │ │ │ └── MyBatisPlusConfig.java
│ │ │ ├── statemachine/
│ │ │ │ ├── StateMachine.java
│ │ │ │ ├── TransitionRule.java
│ │ │ │ ├── StateTransitionException.java
│ │ │ │ ├── ApplicationStateMachine.java
│ │ │ │ ├── PlanStateMachine.java
│ │ │ │ ├── WorkOrderStateMachine.java
│ │ │ │ └── SettlementStateMachine.java
│ │ │ └── module/
│ │ │ ├── application/
│ │ │ │ ├── controller/ApplicationController.java
│ │ │ │ ├── service/ApplicationService.java
│ │ │ │ ├── service/ApplicationValidationService.java
│ │ │ │ ├── repository/ServiceApplicationMapper.java
│ │ │ │ ├── entity/ServiceApplicationEntity.java
│ │ │ │ └── dto/{CreateRequest,SubmitRequest,Response,ListQuery}.java
│ │ │ ├── assessment/
│ │ │ │ ├── controller/AssessmentController.java
│ │ │ │ ├── service/AssessmentService.java
│ │ │ │ ├── repository/{AssessmentTaskMapper,AssessmentReportMapper}.java
│ │ │ │ ├── entity/{AssessmentTaskEntity,AssessmentReportEntity}.java
│ │ │ │ └── dto/{...}.java
│ │ │ ├── plan/
│ │ │ │ └── ... (同模式)
│ │ │ ├── schedule/
│ │ │ │ ├── controller/ScheduleController.java
│ │ │ │ ├── service/ScheduleService.java
│ │ │ │ ├── service/DispatchService.java
│ │ │ │ ├── algorithm/DispatchAlgorithm.java
│ │ │ │ ├── algorithm/HardConstraintFilter.java
│ │ │ │ ├── algorithm/SoftScoringRanker.java
│ │ │ │ └── ...
│ │ │ ├── workorder/
│ │ │ ├── execution/
│ │ │ ├── exception/
│ │ │ ├── supervision/
│ │ │ ├── acceptance/
│ │ │ ├── settlement/
│ │ │ ├── archive/
│ │ │ ├── notification/
│ │ │ │ ├── service/NotificationService.java
│ │ │ │ ├── sender/NotificationSender.java
│ │ │ │ ├── sender/MqttSender.java
│ │ │ │ ├── sender/WechatSender.java
│ │ │ │ └── sender/SmsSender.java
│ │ │ ├── audit/
│ │ │ ├── compliance/
│ │ │ ├── masterdata/
│ │ │ └── capacity/
│ │ └── resources/
│ │ ├── application.yml
│ │ ├── application-dev.yml
│ │ ├── application-test.yml
│ │ ├── application-prod.yml
│ │ └── db/migration/
│ │ ├── V1__baseline.sql
│ │ ├── V2__seed_master_data.sql
│ │ └── V3__add_indexes.sql
│ └── test/java/com/meizhou/hss/
│ ├── statemachine/
│ │ ├── ApplicationStateMachineTest.java
│ │ ├── PlanStateMachineTest.java
│ │ ├── WorkOrderStateMachineTest.java
│ │ └── SettlementStateMachineTest.java
│ ├── module/
│ │ ├── application/ApplicationControllerTest.java
│ │ ├── workorder/WorkOrderIntegrationTest.java
│ │ └── settlement/SettlementCalculationTest.java
│ └── algorithm/DispatchAlgorithmTest.java
└── delivery-miniapp/
├── pages/delivery/
│ ├── login/
│ ├── index/ # 工作台
│ ├── orders/ # 工单列表
│ ├── order-detail/ # 工单详情
│ ├── accept/ # 接单确认
│ ├── checkin/ # GPS签到
│ ├── execute/ # 服务执行
│ ├── exception/ # 异常上报
│ ├── finish/ # 签退完成
│ ├── offline-sync/ # 离线补传
│ ├── messages/ # 通知消息
│ └── profile/ # 我的资质
└── ...
```
---
## 12. 实施优先级与分批计划(补齐版)
### 12.1 第一批MVP 可验收闭环)- 预计 4~6 周
第一批目标不是做全量美化和智能化,而是完成一条真实可验收的居家上门服务闭环:
```text
申请 → 评估 → 方案 → 签署 → 服务计划 → 工单 → 派单 → delivery 接单 → 签到 → 项目执行 → 完成 → 验收 → 结算 → 归档
```
必须包含:
1. 项目初始化:`pom.xml``application.yml`、启动类、环境配置。
2. 公共模块:`ApiResponse``BaseEntity`、统一异常、错误码、分页、租户上下文。
3. 数据库基线Flyway migration包含 P0/P1 核心表。
4. 状态机:申请、方案、工单、结算四层状态机。
5. 状态动作编排:`ActionHandler`,完成状态流转 + 副作用写入。
6. 幂等模块:`hss_idempotency_records` + `Idempotency-Key` 拦截器。
7. Outbox 模块:写入、并发抢占、重试、死信、回执。
8. 审计模块:状态流转、敏感数据访问、高风险操作审计。
9. 申请域:创建、提交、受理通过、退回、取消。
10. 评估域:派发、签到、提交报告、异议。
11. 方案域:创建、编辑、提交签署、签署、拒签、版本管理。
12. 计划域:方案生效后生成服务计划。
13. 工单域:工单创建、派单、接单、拒单、改派。
14. 执行域GPS 签到、项目级执行记录、证据元数据、完成。
15. 异常域:异常上报、异常处理动作、紧急事件基础流程。
16. 验收域:验收确认、拒绝验收、评价。
17. 结算域:结算单、结算明细、审核、支付确认、归档。
18. 支付退款域:支付流水、重复回调幂等、退款/冲正基础表。
19. 定时任务Outbox 重试、派单超时扫描、方案待签提醒、验收超时扫描。
20. delivery 最小闭环页面:登录、工作台、今日工单、详情、接单、签到、执行、异常、完成、证据上传、消息。
21. OpenAPI 契约:覆盖 MVP 全部接口。
22. E2E 测试:完成至少 1 条从申请到归档的完整链路。
### 12.2 第二批(增强能力)- 预计 3~4 周
1. 调度算法:硬约束过滤 + 软约束评分 + Top5 推荐解释。
2. 监管域:抽查计划、违规记录、整改跟踪。
3. 合规域:授权同意、敏感数据访问审计、脱敏策略完善。
4. 主数据域:机构、人员、资质、服务项目、区域、价格、规则版本。
5. 文件证据增强:断点/失败补传、文件 hash、签名 URL、下载审计。
6. 定时任务增强:未来 1~7 天工单生成、次日排班预计算、批量结算。
7. delivery 离线能力:本地缓存、失败补传、重复提交防护。
8. 管理端调度台:改派、撤单、异常处理、超时预警。
9. 权限矩阵落地:接口级权限、字段级脱敏、数据范围过滤。
10. Testcontainers 集成测试PostgreSQL、Redis、MQTT/Mock、对象存储。
### 12.3 第三批(智能化与运营)- 后续迭代
1. 运力域:服务网格、容量预测、网格容量看板。
2. ETA 预测:到达时间、完成时间、风险缓冲。
3. 调度优化局部搜索、插入成本、OR-Tools 批量预排。
4. 数据看板:质量分析、异常热力图、服务连续性、人员负载。
5. 人员绩效结算:服务质量、完成率、投诉率、违规率、评分。
6. 智能助手delivery 端风险提醒、证据缺失提醒、异常处理建议。
---
## 13. 开始实现 Prompt补齐版
### 13.1 第一阶段开工 Prompt
```txt
你现在作为资深 Spring Boot 后端工程师,在全新仓库中实现“居家上门服务系统”的 MVP 第一批。
必须遵守:
1. 技术栈Spring Boot 3.x + Java 17 + PostgreSQL + MyBatis-Plus/Spring Data JDBC + Flyway + Redis + MQTT + 对象存储。
2. 架构:模块化单体,不拆微服务,但按 domain/module 分包。
3. 表规范:所有业务表使用 hss_ 前缀,必须包含 tenant_id、org_id、status、created_by、updated_by、created_at、updated_at、deleted_at、version。
4. 状态机:申请、方案、工单、结算四层状态机;前端只传 action不传目标状态。
5. 状态动作状态机只判断合法性ActionHandler 负责编排副作用例如写业务表、状态流转、Outbox、审计。
6. 幂等:所有写接口支持 Idempotency-Key并落库 hss_idempotency_records。
7. 通知:所有通知必须先写 hss_notification_outbox异步发送Outbox 必须支持并发锁、重试、dead-letter。
8. 结算:结算金额由后端基于方案快照和执行记录计算,禁止使用前端传入金额作为最终金额。
9. 文件证据文件进入对象存储数据库只保存元数据、hash、storage_key、访问审计。
10. delivery 端MVP 必须包含登录、今日工单、详情、接单、签到、执行、异常、完成、证据上传、消息。
11. 测试必须包含状态机单测、金额计算单测、幂等测试、Outbox 失败重试测试、支付重复回调测试、定时任务重复执行测试。
12. 输出Flyway DDL、Java 代码、OpenAPI 契约、状态机文档、数据字典、测试用例。
第一阶段只做 MVP 可验收闭环,不做复杂 ETA、OR-Tools、智能推荐、完整数据看板。
先生成工程目录、pom.xml、application.yml、Flyway V1~V10 migration、BaseEntity、ApiResponse、错误码、幂等拦截器、状态机骨架、Outbox 骨架,然后再实现申请域、评估域、方案域、计划域、工单域、执行域、验收域、结算域。
```
---
## 14. 生产可交付补强清单
### 14.1 P0 必须补齐项
| 编号 | 补齐项 | 必须完成的内容 | 不完成的风险 |
|---|---|---|---|
| P0-01 | 幂等落库 | 新增 `hss_idempotency_records`,所有写接口接入 | 重复提交、重复支付、重复生成工单 |
| P0-02 | 定时任务日志 | 新增 `hss_job_execution_logs` | 定时任务失败不可追溯、不可重跑 |
| P0-03 | Outbox 并发安全 | `locked_by``locked_until``next_retry_at``dead-letter` | 多实例重复发送、通知堆积 |
| P0-04 | delivery MVP | 登录、今日工单、详情、接单、签到、执行、异常、完成、证据上传 | 无法验证真实上门履约 |
| P0-05 | 方案签署事务 | 签署记录、方案生效、服务计划生成、状态流转、Outbox 同事务 | 方案已生效但没有计划 |
| P0-06 | 证据元数据 | `hss_evidence_files` 完整字段、对象存储、hash、签名访问 | 服务执行证据链不可信 |
| P0-07 | 支付幂等 | 支付流水号 + 结算单号幂等 | 重复支付回调导致账务错误 |
| P0-08 | 状态动作编排 | StateMachine + ActionHandler 双层结构 | service 逻辑膨胀,状态副作用失控 |
### 14.2 P1 必须补齐项
| 编号 | 补齐项 | 必须完成的内容 |
|---|---|---|
| P1-01 | 异议闭环 | `hss_objections`,评估异议、方案异议、复核记录 |
| P1-02 | 异常动作 | `hss_exception_actions`,每一次处理动作留痕 |
| P1-03 | 监管整改 | `hss_spot_checks``hss_violations``hss_corrections` |
| P1-04 | 投诉反馈 | `hss_complaints`,与验收拒绝区分 |
| P1-05 | 支付退款 | `hss_payments``hss_refunds`、冲正记录 |
| P1-06 | 归档台账 | `hss_ledgers``hss_archive_files` |
| P1-07 | 主数据 | 服务项目、资质、区域、价格、机构、人员 |
| P1-08 | OpenAPI 完整契约 | 消费者端、管理端、delivery 端、定时任务管理接口 |
---
## 15. 完整 DDL 补齐范围
### 15.1 必须进入 baseline 的核心表
第一版 Flyway 不建议只建少量表再频繁补核心表。MVP 可以不实现全部业务逻辑,但核心表结构应尽量一次性建立,避免后续状态和数据迁移困难。
| 数据域 | 表名 |
|---|---|
| 申请 | `hss_service_applications` |
| 画像 | `hss_patient_profiles` |
| 评估 | `hss_assessment_tasks``hss_assessment_reports` |
| 异议 | `hss_objections` |
| 方案 | `hss_service_plans``hss_service_plan_items``hss_plan_versions` |
| 计划 | `hss_service_schedules` |
| 工单 | `hss_work_orders``hss_work_order_items` |
| 执行 | `hss_checkins``hss_execution_records``hss_evidence_files` |
| 异常 | `hss_exceptions``hss_exception_actions` |
| 监管 | `hss_spot_checks``hss_violations``hss_corrections` |
| 验收 | `hss_acceptances``hss_complaints` |
| 结算 | `hss_settlements``hss_settlement_items` |
| 支付 | `hss_payments``hss_refunds` |
| 归档 | `hss_ledgers``hss_archive_files` |
| 通知 | `hss_notification_outbox``hss_notification_receipts` |
| 幂等 | `hss_idempotency_records` |
| 任务 | `hss_job_execution_logs` |
| 审计 | `hss_state_transitions``hss_audit_logs``hss_data_access_logs` |
| 合规 | `hss_consent_records` |
| 主数据 | `hss_md_organizations``hss_md_staff``hss_md_staff_qualifications``hss_md_service_items``hss_md_price_rules``hss_md_regions` |
| 运力 | `hss_service_grids``hss_grid_capacity_daily``hss_staff_skill_capacity` |
### 15.2 新增关键表字段建议
#### hss_idempotency_records
```sql
CREATE TABLE hss_idempotency_records (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
idempotency_key VARCHAR(128) NOT NULL,
business_key VARCHAR(256) NOT NULL,
request_hash VARCHAR(128) NOT NULL,
response_code VARCHAR(64),
response_body TEXT,
status VARCHAR(32) NOT NULL,
locked_until TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (tenant_id, idempotency_key, business_key)
);
```
#### hss_notification_outbox
```sql
CREATE TABLE hss_notification_outbox (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
business_type VARCHAR(64) NOT NULL,
business_id BIGINT NOT NULL,
event_type VARCHAR(64) NOT NULL,
receiver_id BIGINT NOT NULL,
channel VARCHAR(32) NOT NULL,
payload JSONB NOT NULL,
status VARCHAR(32) NOT NULL,
retry_count INT NOT NULL DEFAULT 0,
max_retry_count INT NOT NULL DEFAULT 5,
next_retry_at TIMESTAMPTZ,
locked_by VARCHAR(128),
locked_until TIMESTAMPTZ,
sent_at TIMESTAMPTZ,
last_error TEXT,
dedupe_key VARCHAR(256) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (tenant_id, dedupe_key)
);
```
#### hss_job_execution_logs
```sql
CREATE TABLE hss_job_execution_logs (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
job_name VARCHAR(128) NOT NULL,
biz_date DATE NOT NULL,
shard_key VARCHAR(128) NOT NULL DEFAULT 'default',
status VARCHAR(32) NOT NULL,
started_at TIMESTAMPTZ NOT NULL,
finished_at TIMESTAMPTZ,
success_count INT NOT NULL DEFAULT 0,
failure_count INT NOT NULL DEFAULT 0,
error_message TEXT,
idempotency_key VARCHAR(256) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (tenant_id, job_name, biz_date, shard_key)
);
```
---
## 16. 状态机与动作编排补齐设计
### 16.1 为什么不能只有 transition 方法
状态机不能只做:
```text
from_status + action = to_status
```
因为每个动作都有副作用。例如“方案签署”必须同时完成:
1. 校验方案版本。
2. 校验签署人。
3. 写签署记录。
4. 冻结方案快照。
5. 生成服务计划。
6. 写状态流转。
7. 写 Outbox。
8. 写审计日志。
### 16.2 推荐双层结构
```text
StateMachine判断动作是否合法
ActionHandler执行业务副作用
```
目录建议:
```text
statemachine/
StateMachine.java
TransitionRule.java
TransitionContext.java
TransitionResult.java
ApplicationStateMachine.java
PlanStateMachine.java
WorkOrderStateMachine.java
SettlementStateMachine.java
action/
ApplicationSubmitHandler.java
ApplicationAcceptHandler.java
AssessmentSubmitHandler.java
PlanSubmitSignHandler.java
PlanSignHandler.java
WorkOrderAssignHandler.java
WorkOrderAcceptHandler.java
WorkOrderCheckInHandler.java
WorkOrderFinishHandler.java
WorkOrderExceptionHandler.java
AcceptanceConfirmHandler.java
SettlementApproveHandler.java
PaymentCallbackHandler.java
```
### 16.3 ActionHandler 标准流程
```text
1. 加载业务对象
2. 校验租户、机构、角色、数据范围
3. 校验 Idempotency-Key
4. 调用 StateMachine 校验动作合法性
5. 执行业务副作用
6. 更新业务状态
7. 写 hss_state_transitions
8. 写 hss_audit_logs
9. 写 hss_notification_outbox
10. 提交事务
11. 返回动作结果
```
---
## 17. Outbox 并发安全与补偿机制
### 17.1 Outbox 发送状态
| 状态 | 含义 |
|---|---|
| CREATED | 已创建,待发送 |
| LOCKED | 已被某个实例抢占 |
| SENT | 已发送成功 |
| FAILED | 本次发送失败,等待重试 |
| DEAD | 超过最大重试次数,进入死信 |
### 17.2 多实例抢占策略
PostgreSQL 推荐使用 `FOR UPDATE SKIP LOCKED`
```sql
SELECT *
FROM hss_notification_outbox
WHERE status IN ('CREATED', 'FAILED')
AND (next_retry_at IS NULL OR next_retry_at <= now())
ORDER BY created_at
LIMIT 100
FOR UPDATE SKIP LOCKED;
```
发送任务拿到记录后更新为 `LOCKED`,设置 `locked_by``locked_until`。发送成功后更新为 `SENT`,失败则增加 `retry_count` 并设置 `next_retry_at`。超过最大重试次数进入 `DEAD`
### 17.3 失败补偿
1. `FAILED` 可自动重试。
2. `DEAD` 必须进入运营或技术告警。
3. 支持按业务 ID 手动重发。
4. 支持按时间区间批量重发。
5. 通知通道失败不能回滚业务主状态。
6. 消费者端和 delivery 端必须能通过主动查询拿到真实业务状态。
---
## 18. delivery 端 MVP 最小闭环
### 18.1 MVP 页面范围
| 页面 | 是否 MVP 必须 | 说明 |
|---|---|---|
| 登录页 | 是 | 校验服务人员角色、机构、状态 |
| 工作台 | 是 | 今日任务、待接单、待签到、服务中、异常 |
| 今日工单 | 是 | 查询本人任务 |
| 工单详情 | 是 | 地址、对象脱敏信息、服务项目、风险提示 |
| 接单/拒单 | 是 | 触发工单状态机 |
| 签到 | 是 | GPS、拍照、对象确认 |
| 执行 | 是 | 项目级执行记录 |
| 异常 | 是 | 对象不在家、拒绝服务、身体异常、地址错误等 |
| 完成 | 是 | 提交服务总结、证据校验 |
| 证据上传 | 是 | 文件上传、hash、元数据 |
| 消息页 | 是 | 派单、改派、异常处理、验收反馈 |
| 离线补传 | 第二批 | MVP 可先做失败重试,不做完整离线队列 |
| 智能助手 | 第三批 | 风险提醒、路径建议、语音输入 |
### 18.2 delivery 聚合接口
```text
GET /api/hss/delivery/workbench
GET /api/hss/delivery/work-orders/today
GET /api/hss/delivery/work-orders/{id}/detail
POST /api/hss/delivery/work-orders/{id}/accept
POST /api/hss/delivery/work-orders/{id}/reject
POST /api/hss/delivery/work-orders/{id}/check-in
POST /api/hss/delivery/work-orders/{id}/start-service
POST /api/hss/delivery/work-orders/{id}/execution-records
POST /api/hss/delivery/work-orders/{id}/finish
POST /api/hss/delivery/work-orders/{id}/exception
POST /api/hss/delivery/evidence/upload
GET /api/hss/delivery/messages
POST /api/hss/delivery/messages/{id}/read
```
---
## 19. 完整 OpenAPI 接口补齐范围
### 19.1 消费者端接口
```text
POST /api/hss/applications
POST /api/hss/applications/{id}/submit
POST /api/hss/applications/{id}/cancel
GET /api/hss/applications/{id}
GET /api/hss/service-plans/{id}/for-sign
POST /api/hss/service-plans/{id}/sign
POST /api/hss/service-plans/{id}/reject
GET /api/hss/work-orders/{id}/acceptance
POST /api/hss/work-orders/{id}/acceptance/confirm
POST /api/hss/work-orders/{id}/acceptance/reject
POST /api/hss/work-orders/{id}/rating
GET /api/hss/settlements/{id}
POST /api/hss/settlements/{id}/pay
```
### 19.2 管理端接口
```text
GET /api/hss/admin/applications
POST /api/hss/admin/applications/{id}/accept
POST /api/hss/admin/applications/{id}/return
POST /api/hss/admin/assessment-tasks/{id}/assign
POST /api/hss/admin/service-plans
PUT /api/hss/admin/service-plans/{id}
POST /api/hss/admin/service-plans/{id}/submit-sign
POST /api/hss/admin/service-plans/{id}/generate-schedule
POST /api/hss/admin/work-orders/{id}/assign
POST /api/hss/admin/work-orders/{id}/reassign
POST /api/hss/admin/work-orders/{id}/cancel
POST /api/hss/admin/exceptions/{id}/handle
POST /api/hss/admin/settlements/generate
POST /api/hss/admin/settlements/{id}/approve
POST /api/hss/admin/settlements/{id}/reject
GET /api/hss/admin/audit-logs
```
### 19.3 文件与证据接口
```text
POST /api/hss/files/presign-upload
POST /api/hss/files/commit
GET /api/hss/files/{id}/signed-url
GET /api/hss/evidence-files/by-work-order/{workOrderId}
```
### 19.4 主数据接口
```text
GET /api/hss/master/service-items
GET /api/hss/master/price-rules
GET /api/hss/master/regions
GET /api/hss/master/staff
GET /api/hss/master/staff/{id}/qualifications
```
---
## 20. 定时任务补齐设计
### 20.1 必须实现的 MVP 任务
| 任务 | 频率 | MVP 是否必须 |
|---|---|---|
| Outbox 重试 | 每 1 分钟 | 是 |
| 派单超时扫描 | 每 5 分钟 | 是 |
| 方案待签提醒 | 每 30 分钟 | 是 |
| 服务开始前提醒 | 每 10 分钟 | 是 |
| 验收超时扫描 | 每小时 | 是 |
| 未来工单生成 | 每晚 00:30 | 第二批也可,但表和接口先预留 |
| 次日排班预计算 | 每晚 01:00 | 第二批 |
| 批量结算生成 | 每日/每月 | 第二批 |
| 审计日志归档 | 每月 | 第二批 |
### 20.2 任务执行规则
1. 所有任务写 `hss_job_execution_logs`
2. 所有任务按 `job_name + biz_date + shard_key` 幂等。
3. 所有任务支持 dry-run。
4. 所有任务支持手动重跑。
5. 所有任务不得绕过状态机直接改状态。
6. 多实例部署必须使用分布式锁或数据库唯一键防重复。
---
## 21. 测试与验收补齐
### 21.1 新增必测用例
| 类型 | 用例 |
|---|---|
| 幂等 | 同一 Idempotency-Key 重复提交返回同一结果 |
| 幂等冲突 | 同一 Idempotency-Key 不同 body 返回冲突 |
| 并发派单 | 两个调度员同时派同一工单,只能成功一次 |
| 并发接单 | 服务人员重复点击接单,只生成一次接单记录 |
| 并发完成 | 重复完成提交不生成重复执行记录 |
| Outbox 失败 | MQTT 失败后 Outbox 进入 FAILED 并可重试 |
| Outbox 死信 | 超过最大次数进入 DEAD |
| 支付回调 | 同一支付流水重复回调只入账一次 |
| 事务回滚 | 服务计划生成失败时方案签署整体回滚 |
| 文件补传 | 文件上传成功但业务提交失败,可重新绑定 |
| 权限 | 服务人员不能查看非本人工单 |
| 脱敏 | 非授权角色看不到完整手机号、地址、健康信息 |
| 任务重跑 | 同一天重复生成工单不产生重复数据 |
| 弱网 | delivery 端重复点击、网络失败、恢复补传 |
### 21.2 MVP 验收门槛
1. 状态机核心分支单测覆盖率 ≥ 90%。
2. 结算金额计算单测覆盖率 ≥ 90%。
3. 所有写接口必须有幂等测试。
4. 所有状态动作必须有非法状态测试。
5. delivery 端完成 5 条 E2E接单、签到、执行、异常、完成。
6. Outbox 完成失败重试和死信测试。
7. 支付回调完成重复回调测试。
8. 定时任务完成重复执行测试。
9. 权限和脱敏至少覆盖服务人员、调度员、结算员、监管员四类角色。
10. OpenAPI 与实际接口保持一致。
---
## 22. 灰度发布与回滚补齐
### 22.1 发布策略
| 能力 | 发布方式 |
|---|---|
| 状态机 | 测试环境全量验证后上线,不做灰度状态 |
| 调度算法 | shadow 模式 → 人工确认 → 小范围自动 |
| 自动验收 | 默认关闭,试点机构开启 |
| 批量结算 | dry-run → 人工审核 → 自动生成 |
| delivery 新页面 | 按机构/角色灰度 |
| 定时任务 | 小范围 biz_date dry-run 后开启 |
| Outbox | 先发送测试通道,再切真实通道 |
### 22.2 回滚原则
1. 数据库以 roll-forward 为主,不依赖直接 down migration。
2. 已上线的 migration 不修改,新增 migration 修正。
3. 删除字段必须两阶段:先停用,后删除。
4. 新状态上线前必须确认旧代码能兼容或不会读取。
5. 功能必须有 feature flag。
6. 回滚后不能产生孤儿状态。
7. 任务必须可暂停、可恢复、可重跑。
---
## 23. 最终开工检查清单
开始实现前,必须确认以下事项:
| 检查项 | 是否必须 |
|---|---|
| 已确认 Spring Boot / Java 17 / PostgreSQL / Redis / MQTT / 对象存储 | 是 |
| 已确认 hss_ 表前缀、统一审计字段、软删除、乐观锁 | 是 |
| 已确认方案、计划、工单分离 | 是 |
| 已确认工单项目级执行记录 | 是 |
| 已确认所有写接口 Idempotency-Key | 是 |
| 已确认新增 `hss_idempotency_records` | 是 |
| 已确认新增 `hss_job_execution_logs` | 是 |
| 已确认 Outbox 支持锁、重试、死信 | 是 |
| 已确认 delivery MVP 进入第一批 | 是 |
| 已确认支付、退款独立表 | 是 |
| 已确认异常、监管、投诉独立闭环 | 是 |
| 已确认 OpenAPI 全契约先行 | 是 |
| 已确认 Testcontainers/真实依赖集成测试 | 是 |
| 已确认灰度开关和 roll-forward 回滚策略 | 是 |
---
## 24. 最终结论
这份补齐版已经可以作为正式开工文档使用。实现时不要再扩大需求范围,第一阶段只围绕“真实可验收闭环”推进:
```text
后端状态机可信
数据库链路完整
通知可靠可补偿
delivery 可真实履约
结算可追溯
异常可兜底
权限与审计可验收
测试能证明系统可靠
```
第一阶段完成后,系统应能真实跑通:
```text
家属提交申请
→ 受理员受理
→ 评估员评估
→ 管理端生成方案
→ 家属签署方案
→ 系统生成服务计划和工单
→ 调度员派单
→ delivery 服务人员接单
→ GPS 签到
→ 项目级执行
→ 上传证据
→ 完成服务
→ 家属验收
→ 系统生成结算
→ 支付确认
→ 归档
```
只要严格按本补齐版执行,就可以开始实现。