Files
Home-Care/IMPLEMENTATION_PLAN.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

1412 lines
55 KiB
Markdown
Raw Permalink 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
> 基于V2.0 工程落地增强版 + V2.1 行业经验增强版 + V2.2 边界限制增强版
> 项目状态:全新仓库,从零搭建
---
## 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. 实施优先级与分批计划
### 第一批MVP 核心链路)- 预计 4~6 周
1. 项目初始化pom.xml、application.yml、启动类
2. 公共模块ApiResponse、BaseEntity、异常、幂等、审计切面
3. 数据库基线V1__baseline.sql全部核心表
4. 状态机:四层状态机 + 状态流转记录
5. 申请域:创建、提交、受理通过/退回、取消
6. 评估域:派发评估、签到、提交报告、异议
7. 方案域:创建、编辑、提交签署、签署/拒签、版本管理
8. 计划域:服务计划生成
9. 工单域:工单创建、派单、接单/拒单
10. 执行域:签到、逐项执行记录、完成
11. 验收域:验收确认/拒绝、评价
12. 结算域:生成结算单、审核、支付确认、归档
13. 通知域Outbox 写入 + 定时发送
14. 审计域:状态流转记录 + 审计日志
### 第二批(增强能力)- 预计 3~4 周
1. 调度算法:硬约束过滤 + 软约束评分 + Top5推荐
2. 监管域:抽查计划、违规记录、整改跟踪
3. 合规域:授权同意、敏感数据访问审计
4. 主数据域:机构、人员、资质、服务项目、区域、价格
5. 异常域:异常上报、处理动作、紧急事件
6. delivery 端小程序开发
### 第三批(智能化与运营)- 后续迭代
1. 运力域:服务网格、容量预测
2. ETA 预测
3. 调度算法优化(局部搜索/OR-Tools
4. 数据看板和质量分析
5. 人员绩效结算
---
## 13. 短 Prompt
```txt
基于 /home/akoo/居家服务/IMPLEMENTATION_PLAN.md 实现 MVP 第一批(项目初始化 + 公共模块 + 数据库基线 + 状态机 + 申请域 + 评估域)。
技术栈Spring Boot 3.3 + Java 17 + MyBatis-Plus + PostgreSQL + Flyway。
- 严格遵循 hss_ 表前缀和审计字段规范
- 前端只传动作不传目标状态
- 所有写接口带 Idempotency-Key
- 通知走 Outbox 模式
- 输出 Flyway V1 迁移脚本 + Java 代码
```