Files
th-hotel-simple/docs/project/backend-development-guidelines.md

321 lines
16 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.

# TH Hotel 后端开发规范
## 1. 文档定位
本文整理 TH Hotel 当前后端开发约定,供本项目后端开发和其他 agent 协作参考。
本文是当前项目专属补充,不应整份复制到其他项目。可复用的通用后端规则应沉淀到 `docs/import/reusable/backend-development-guidelines.md`
本项目后端是酒店多部门 AI 业务流程与 Case 协同平台的服务端。这里的 AI 只表示调用外部
模型或 Agent 能力提供方并消费其结构化结果本项目不开发模型、Prompt 优化平台、Agent
Runtime、Planner、Memory 或通用工具调用框架。
## 2. 技术栈
`server/pom.xml` 为准,当前后端技术栈如下:
| 类别 | 当前选择 |
| --- | --- |
| Java | Java 17 LTS语法版本 Java 17 |
| 框架 | Spring Boot 3.5.15 |
| Web | Spring MVC |
| 构建 | Maven Wrapper |
| 外部 HTTP | Spring `RestClient` 优先 |
| 数据库 | MySQL 8.0+ |
| ORM / Mapper | MyBatis-Plus 3.5.16Spring Boot 3 使用 `mybatis-plus-spring-boot3-starter` |
| 数据库迁移 | Flyway |
| OpenAPI | springdoc-openapi 2.8.17 |
| 测试 | JUnit 5、Spring Boot Test、H2 MySQL Mode |
升级 Java、Spring Boot、MyBatis-Plus、springdoc 或 Flyway 前,必须先做兼容性验证。
Maven 编译配置应显式使用 `maven.compiler.release=17`,并开启参数名保留,例如 `parameters=true`。除非单独确认升级方案,否则不得使用 Java preview 特性或 Java 21 / Java 25 专属语法。
引入 MyBatis-Plus 后,不再额外引入 `mybatis-spring-boot-starter``MyBatis-Spring` 或重复的原生 MyBatis starter避免 starter 版本差异造成运行期问题。
## 3. 后端分层与包边界
推荐边界:
```text
platform
├── ai
├── audit
├── evidence
├── message
├── operation
├── receipt
└── system
workflows
└── reservation
integrations
├── ai
├── document
├── external
├── messaging
└── ohip
```
中文说明:
| 层级 | 中文职责 | 依赖规则 |
| --- | --- | --- |
| `platform` | 平台通用能力层保存消息、证据、AI 调用审计、Operation、Receipt、审计等部门中立能力 | 可以被业务流程调用,不能反向依赖预订部等具体业务流程 |
| `workflows` | 业务流程层,保存具体部门或业务线的流程编排,当前优先是预订流程 | 可以依赖 `platform` 和稳定端口,不直接依赖外部系统 DTO |
| `integrations` | 外部系统适配层,隔离 OHIP、SuperAgent、AgentBus 等外部协议和认证细节 | 可以实现平台或业务端口,不能把外部 DTO 泄漏到领域模型 |
后续输出包结构、目录树、数据模型、字段映射或接口示例时,必须补充中文说明,说明每层职责、依赖方向、可调用对象和禁止事项,不能只依赖英文命名表达含义。
职责规则:
- `platform` 保存部门中立能力例如消息、证据、AI 调用审计、Operation、Receipt、审计。
- `workflows` 保存部门业务流程,当前明确的是 `reservation`
- `integrations` 保存外部系统适配器,例如 OHIP、SuperAgent、AgentBus外部协议转换类应放入具体集成模块的 `adapter` 包。
- 平台核心不得依赖预订部专有字段。
- 部门工作流可以依赖平台核心,平台核心不能反向依赖部门模块。
- 外部系统 DTO、Oracle DTO、Provider DTO、领域模型和 API Response 必须分离。
- Oracle DTO 或生成代码只能位于 `integrations.ohip`,不得进入平台领域模型。
- 外部协议到内部命令或 DTO 的转换类使用 `Adapter``Converter` 等能表达适配语义的后缀,不使用 `Mapper` 命名,避免和 MyBatis Mapper 混淆。
当前项目后端模块内部目录强制按以下结构组织:
```text
<module>
├── control
├── service
│ └── impl
├── domain
├── mapper
├── repository
└── common
├── dto
├── request
├── result
└── enums
```
中文说明:
| 目录 | 中文职责 | 放置内容 |
| --- | --- | --- |
| `control` | HTTP 入口层 | Controller 具体实现类,只处理请求契约、参数校验和响应映射 |
| `service` | 服务契约层 | Service 接口,只表达模块对外提供的稳定业务能力 |
| `service.impl` | 服务实现层 | Service 实现类负责编排事务、幂等、Repository 和外部端口 |
| `domain` | 数据实体层 | Entity 类,字段必须有中文注释,不能与 Response 或外部 DTO 混用 |
| `mapper` | MyBatis 访问层 | Mapper 类和语义化 Mapper 方法Controller 与 Service 不直接跨层暴露 Mapper |
| `repository` | 持久化封装层 | Repository 接口和具体实现,对 Service 屏蔽 Mapper 与数据库细节 |
| `common.dto` | 通用数据载体层 | 模块内部跨层传递的 DTO、快照、草稿等数据载体 |
| `common.request` | 请求模型层 | Controller、Service 或外部适配器输入侧的 Request、Command、Query 条件 |
| `common.result` | 结果模型层 | Service 或 Controller 输出侧的 Result、分页结果、操作结果 |
| `common.enums` | 模块枚举层 | 本模块稳定业务枚举、状态码和失败原因枚举 |
后续生成或移动 Java 代码时必须严格遵守上述目录,不再新增 `api``application``persistence` 等同义包来承载这些职责,除非先更新本规范并说明迁移原因。已有或迁移来的 `application` 包中的 Request、Result、DTO 类,应按语义移动到对应模块的 `common.request``common.result``common.dto`。如果类职责或目录归属不明确,必须先询问再继续。
## 4. Controller / Service / Repository 规则
- Controller 只做 HTTP 契约、参数校验、权限入口和响应映射。
- Controller 不直接访问 Mapper。
- Controller 不直接调用外部适配器。
- Service 接口位于 `service` 包,表达模块对外提供的稳定业务能力。
- Service 实现类位于 `service.impl`编排事务、Entity、Repository 和外部端口。
- Request、Command、Query 条件位于 `common.request` 包。
- Result、分页结果、操作结果位于 `common.result` 包。
- 跨层 DTO、Snapshot、Draft 等通用数据载体位于 `common.dto` 包。
- Entity 位于 `domain` 包,表达数据库表字段与业务含义,不与 DTO、Response 或外部 Provider DTO 混用。
- Mapper 位于 `mapper` 包,只负责本模块数据库表访问和语义化查询方法。
- Repository 位于 `repository` 包,负责封装 Mapper 和数据库细节,作为 Service 的持久化边界。
- 外部调用通过端口和 Adapter 隔离,业务层不依赖厂商 SDK 或厂商 DTO。
- 外部协议适配类位于对应 `integrations.<capability>.<provider>.adapter` 包,负责把外部 DTO 或 JSON 转换为内部稳定命令。
- 生成或迁移代码前必须先阅读本规范并查看同模块既有代码习惯;如果放置目录、类名后缀或依赖方向不确定,先询问再实现。
## 5. 数据建模规则
必须分别建模以下业务标识,不能共用模糊字段:
```text
caseId
blockId
reservationId
confirmationNumber
groupCode
```
其他规则:
- 房型、房量、人数、金额、日期必须使用结构化字段,不只保存展示字符串。
- 状态使用稳定英文代码,中文和英文只用于显示。
- 动态参数必须有稳定 `fieldKey` 和可国际化 `labelKey`
- 不能把某一种语言的显示文本当作接口契约或业务判断依据。
- 至少区分外部提供方建议值、人工确认值、最终执行值。
- Receipt 生成后不可覆盖修改;纠错通过新记录表达。
- Task 执行必须支持幂等、并发版本校验和审计。
## 6. SourceMessage / AI / Task 边界
- `SourceMessage` 表示 Email、LINE、附件等渠道输入的原始来源事实。
- AI 抽取输出的业务事件不是来源消息,也不是正式 Task。
- 一条 SourceMessage 可以产生多个 AI Task Result、多个候选或多张 Task。
- Task 与 SourceMessage、AI MessageEvent、Evidence 通过来源关联建模。
- 不得用单个 `createdFromEventId` 固化一对一关系。
- Case 匹配不明确时,必须创建可持久化、可审计的 Preflight / Need Manual Review 对象。
- 只有人工关联已有 Case 或确认新增 Case 后,才创建正式 TaskCard。
- Preflight / Need Manual Review 被拒绝或终止后不得删除,必须保留来源、候选版本、处理人、原因和时间。
## 7. AI / Agent Provider 边界
- 业务模块只依赖 `AiCapabilityPort` 一类稳定调用契约。
- SuperAgent、模型 ID、Agent ID、认证配置位于 Adapter 层。
- 真实 Provider 返回内容不得直接生成 Recognition、Case、Task、Operation、Receipt 或 OHIP 写入。
- Provider 输出只能作为建议或证据。
- 所有会引起业务写操作的参数必须经过规则校验和人工确认。
- 平台可记录 provider、capability、request id、版本、耗时和用量但不实现模型训练、Prompt 优化或 Agent 编排。
## 8. AgentBus 边界
- AgentBus 是消息入口适配器,不是 AI Provider。
- 实时 AgentBus 链路只写 `platform_source_message_inbox`
- 不直接生成 `platform_message_event`、Evidence、Recognition、Case、Task、Operation、Receipt 或 OHIP 写入。
- 不自动发送 ACK、`task.result` 或客户回复。
- SourceMessage Inbox 到 MessageEvent / Evidence 必须通过受控 replay。
- 原始 frame 本地采样默认关闭,生产不常态保存 raw frame。
## 9. OHIP / OPERA Cloud 边界
开发任何 OHIP 页面或执行器前,必须先更新字段映射文档,明确:
- 页面字段
- 领域字段
- 内部 API 字段
- OHIP 字段或 JSONPath
- 来源接口和版本
- 是否必填
- fallback
- Sandbox 验证状态
- UAT 三方核对状态
禁止根据字段名猜 Oracle API 字段。未通过官方文档或真实响应确认的内容必须标记为“待确认”。
浏览器不得直接调用 OHIP。OHIP Secret 只能由后端环境变量或部署平台 Secret 注入。
## 10. 数据库与 Flyway 规范
- 新建表和改表必须通过 Flyway migration。
- 已发布 migration 禁止直接修改。
- 修正注释、索引或约束必须新增 migration。
- 每张业务表必须有中文表级 `COMMENT`
- 每个业务字段必须有中文字段级 `COMMENT`
- SQL 文件应使用中文行注释划分表、索引、约束等主要结构。
- 注释必须说明业务含义、来源或代码值范围。
- 禁止使用“字段1”“备用字段”等模糊注释。
- 业务时间点以 UTC 写入数据库API 层负责返回带 `Z` 的 ISO 8601 UTC 时间,例如 `2026-07-08T03:00:00Z`
- 新增 API 响应 DTO 中的时间点字段优先使用 `OffsetDateTime`;从数据库 `LocalDateTime` 快照输出到接口时,应通过 `UtcTimeFormatter` 转换,禁止直接把无时区 `LocalDateTime` 暴露给前端或 SuperAgent。
- 酒店本地业务日期,例如入住日期、离店日期、营业日,优先使用 `LocalDate` 或明确酒店时区语义的字段,不和 UTC 时间点混用。
- JSON 字段只用于扩展元数据,不替代需要查询、约束或索引的正式列。
## 11. 后端代码注释规范
后端 Java 代码必须提供必要且准确的中文注释:
- 架构文档、设计文档、目录结构、数据模型、字段映射和接口示例必须优先使用中文说明业务含义。
- 领域对象、应用服务、外部适配器、Controller、配置属性和复杂参数对象应说明业务含义、边界或调用约束。
- `control``service``service.impl` 中的方法必须有中文注释,说明业务动作、调用边界、幂等或安全约束。
- `mapper` 中 MyBatis-Plus 自带继承方法不强制补中文注释;不要为了重命名 `selectById``insert``updateById` 等自带方法而写薄 default 包装。本项目自定义的语义化查询、写入、更新方法应根据业务复杂度合理补充中文注释。
- `domain` 中 Entity 的每个字段必须有中文注释,说明字段业务含义、来源、代码值范围或安全限制。
- `repository` 中对外暴露的方法必须有中文注释,说明持久化语义和是否返回安全字段。
- 复杂流程、幂等键、并发控制、事务边界、错误转换、外部系统字段映射和安全脱敏逻辑必须说明原因。
- 注释不得只复述类名、方法名或字段名。
- 不得用“TODO 待完善”替代真实说明。
- 生成新后端代码时必须同步生成中文注释。
- 修改旧代码时,应补齐触达代码的必要中文注释。
## 12. 安全与日志
Secret 只能通过 `.env`、环境变量或部署平台 Secret 注入。仓库只提交无真实值的 `.env.example`
禁止提交:
- 真实酒店凭证
- Oracle Client Secret、Application Key、Integration Password
- SuperAgent API Key
- AgentBus Token
- Cookie、Access Token
- 真实客户邮件、附件 URL、个人数据
- 完整支付信息
日志必须脱敏:
- Authorization、Cookie
- Client Secret、Integration Password、Application Key
- 客人姓名、邮箱、电话、证件信息
- 支付卡和账务敏感数据
- 原始消息正文、HTML、附件 URL
## 13. 配置规范
- Spring Boot 不会自动读取 `.env`,本地启动需由 shell、IDE、容器或部署平台注入环境变量。
- 本地开发可复制根目录 `.env.example``.env`,真实值只留本机。
- `TH_HOTEL_DB_URL` 包含 `&` 时必须加引号。
- 后端 Secret 不得放入前端 `VITE_*`
- 生产环境应拆分 ConfigMap / 非敏感环境变量与 Secret / 密钥管理系统。
## 14. API 设计规范
- API 返回稳定代码,不返回中文或英文文本作为前端业务判断依据。
- 动态表单字段使用稳定 `fieldKey` 和可国际化 `labelKey`
- 错误响应不得回显 Secret、原始正文、附件 URL 或个人信息。
- 写接口必须考虑幂等、并发版本、审计和失败恢复。
- 外部写操作结果不明确时,禁止盲目重试。
- 调试接口必须默认关闭,并使用独立访问密钥。
## 15. 测试与检查命令
后端最低检查:
```bash
cd server
./mvnw test
./mvnw verify
```
聚焦开发时可先运行相关测试:
```bash
cd server
./mvnw -Dtest=SomeFocusedTest test
```
默认 `test` profile 使用 H2 MySQL Mode保证普通测试不依赖本机 MySQL。需要连接真实测试 MySQL 时,使用 `test,test-mysql` profile并通过 `TH_HOTEL_TEST_DB_URL``TH_HOTEL_TEST_DB_USERNAME``TH_HOTEL_TEST_DB_PASSWORD` 注入测试库连接信息。测试 MySQL 只能使用本地或 CI 测试库,不得连接生产库或包含真实酒店、客户、支付数据的数据库。
如果命令尚未配置或因环境问题无法运行,必须明确说明,不能假装通过。
## 16. Git 与协作流程
- 改动前说明目标、范围和将修改的文件。
- 每次只处理一个模块或一个纵向切片。
- 需求基准变化时,先做差异和影响分析。
- 修改接口前确认领域模型和数据映射。
- 不修改与当前任务无关的用户变更。
- 修改后运行项目已配置的检查命令。
- Git commit message 使用中文,清楚说明本次提交的业务或技术变更。
## 17. 后端提交前检查清单
- [ ] 是否遵守 platform / workflows / integrations 分层?
- [ ] 模块内部是否遵守 `control` / `service` / `service.impl` / `domain` / `mapper` / `repository` / `common.dto` / `common.request` / `common.result` / `common.enums` 目录规则?
- [ ] Controller 是否没有直接访问 Mapper 或外部 Adapter
- [ ] Request、Result、DTO 是否放在 `common.request``common.result``common.dto`,而不是混在 `service` 或临时 `application` 包?
- [ ] `control``service``service.impl``repository` 方法是否有中文注释?
- [ ] Mapper 自定义语义化方法是否按复杂度合理补充中文注释,且未为了 MyBatis-Plus 自带继承方法强行加无意义注释?
- [ ] 外部协议适配类是否放在 `integrations.<capability>.<provider>.adapter`,并避免使用 `Mapper` 命名混淆 MyBatis Mapper
- [ ] Entity 字段是否有中文注释?
- [ ] 外部 DTO 是否没有进入领域模型?
- [ ] 写接口是否有幂等、版本或审计设计?
- [ ] Flyway SQL 是否有规范中文注释?
- [ ] Java 复杂逻辑是否有必要中文注释?
- [ ] 是否没有提交真实 Secret 或客户数据?
- [ ] 是否没有把 Provider 输出直接当业务事实?
- [ ] 是否运行了 `./mvnw test` 或说明了无法运行原因?
- [ ] 是否运行了 `./mvnw verify` 或说明了无法运行原因?