文档更新

This commit is contained in:
2026-06-04 14:34:32 +08:00
parent 7b91c310eb
commit e01ca79bdc
7 changed files with 1036 additions and 2 deletions

View File

@@ -0,0 +1,322 @@
> For AI assistants: Read this entire file before writing any code. All decisions here are final.
# Fonrey — 统一状态机规范 (STATE_MACHINE)
**定位**:本文档是 Fonrey 项目所有实体生命周期与状态流转的唯一权威定义。
**变更历史**
| 日期 | 变更人 | 变更内容 |
|---|---|---|
| 2026-06-04 | Sisyphus | 初始版本:整合各模块状态机逻辑,对齐 ENUMS v2.2 |
---
## 1. 通用约定
- **状态值命名**:统一采用 `lower_snake_case`,必须与 `DATA_MODEL/ENUMS.md` 完全一致。
- **触发动作**状态迁移必须由显式的动作Action或事件Event触发。
- **操作日志**:所有关键状态迁移(除系统内部中间态外)必须记录对应的 `status_log``audit_log` 表。
- **不可逆规则**:标注为“终态”的状态禁止迁回初始态或中间态。
- **权限要求**:状态迁移接口必须校验操作者的 DataScope 与 Function Permission。
---
## 2. 租户生命周期 (Public.Tenant)
**实体**: `public.tenants` | **字段**: `status`
**参考**: `DATA_MODEL_PUBLIC.md` §2.1, §4.1
```mermaid
stateDiagram-v2
[*] --> creating
creating --> active: 初始化完成
creating --> failed: 初始化失败
active --> suspended: 逾期/违规/申请
suspended --> active: 恢复条件满足
active --> pending_delete: 申请注销
suspended --> pending_delete: 申请注销
pending_delete --> deleted: 30天后/人工确认
deleted --> [*]
```
### 状态枚举值
(domain: `public.tenant.status`)
- `creating`: 创建中
- `active`: 正常
- `suspended`: 已挂起
- `pending_delete`: 待删除
- `deleted`: 已删除
- `failed`: 创建/初始化失败
### 状态迁移表
| 当前状态 | 下一状态 | 触发动作/事件 | 触发角色 | 副作用 | 是否可逆 |
|---|---|---|---|---|---|
| `creating` | `active` | 租户 Schema 初始化成功 | System | 写 `tenant_status_logs` | 否 |
| `creating` | `failed` | 初始化脚本执行失败 | System | 记录错误日志 | 否 |
| `active` | `suspended` | 欠费/违规/License过期 | System/SuperAdmin | 设置 `suspended_until`, 写日志 | 是 |
| `suspended` | `active` | 缴费成功/解封/到期恢复 | System/SuperAdmin | 清除挂起原因 | 是 |
| `active`/`suspended` | `pending_delete` | 提交注销申请 | TenantAdmin | 设置 `deleted_at` | 是 |
| `pending_delete` | `deleted` | 确认注销/静默期结束 | SuperAdmin/System | 物理删除或深度标记 | 否 |
**来源章节**: `DATA_MODEL_PUBLIC.md` §4.1
---
## 3. 客源状态机 (Client)
**实体**: `client.clients` | **字段**: `status`
**参考**: `DATA_MODEL_CLIENT.md` §3.1, §4 | `ENUMS.md` §3.6
```mermaid
stateDiagram-v2
[*] --> buying
[*] --> renting
[*] --> buy_or_rent
state "活跃态" as Active {
buying
renting
buy_or_rent
}
Active --> suspended: 暂时无需求
suspended --> Active: 重新激活
Active --> public: 手动转公/超时自动
suspended --> public: 手动转公
Active --> bought: 转成交(我购)
Active --> rented_done: 转成交(我租)
Active --> invalid: 转无效
suspended --> invalid: 转无效
invalid --> Active: 经理审批恢复
bought --> [*]
rented_done --> [*]
public --> [*]
```
### 状态枚举值
(domain: `client.status`)
- `buying`: 求购
- `renting`: 求租
- `buy_or_rent`: 租购
- `suspended`: 暂缓
- `bought`: 已购 (我购)
- `rented_done`: 已租 (我租)
- `public`: 公客
- `invalid`: 无效
### 状态迁移表
| 当前状态 | 下一状态 | 触发动作/事件 | 触发角色 | 副作用 | 是否可逆 |
|---|---|---|---|---|---|
| `buying`/`renting`/`buy_or_rent` | `suspended` | 修改状态为暂缓 | 经纪人 | 写 `client_status_logs` | 是 |
| `suspended` | `buying`/`renting`/`buy_or_rent` | 重新激活需求 | 经纪人 | 更新 `last_active_at` | 是 |
| `Active`/`suspended` | `public` | 手动转公/超时自动转公 | 经纪人/System | 修改 `client_type='public'` | 否 |
| `Active` | `bought`/`rented_done` | 录入成交合同 | 经纪人 | 修改 `client_type='transacted'` | 否 |
| `Active`/`suspended` | `invalid` | 标记无效 | 经纪人 | 记录 `invalid_reason` | 需审批 |
### 禁迁规则
- `transacted` (bought/rented_done) 状态为绝对终态,禁止迁往任何其他状态。
- `public` 状态客源禁止直接修改为 `private` 状态下的需求状态,必须走领用流程。
**来源章节**: `DATA_MODEL_CLIENT.md` §4, `ENUMS.md` §3.6
---
## 4. 房源状态机 (Property)
**实体**: `property.properties` | **字段**: `status`
**参考**: `DATA_MODEL_PROPERTY.md` §3, §4.1
```mermaid
stateDiagram-v2
[*] --> unlisted
unlisted --> for_sale: 挂牌出售
unlisted --> for_rent: 挂牌出租
state "在盘态" as Listed {
for_sale
for_rent
for_sale_rent
}
Listed --> suspended: 业主暂缓
suspended --> Listed: 重新上架
Listed --> sold: 本司成交
Listed --> sold_elsewhere: 他售
Listed --> rented_elsewhere: 他租
Listed --> unlisted: 下架
sold --> [*]
sold_elsewhere --> [*]
```
### 状态枚举值
(domain: `property.status`)
- `for_sale`: 出售
- `for_rent`: 出租
- `for_sale_rent`: 租售
- `suspended`: 暂缓
- `sold_elsewhere`: 他售
- `rented_elsewhere`: 他租
- `sold`: 成交
- `unlisted`: 未挂牌
### 状态迁移表
| 当前状态 | 下一状态 | 触发动作/事件 | 触发角色 | 副作用 | 是否可逆 |
|---|---|---|---|---|---|
| `unlisted` | `for_sale`/`for_rent` | 房源挂牌 | 经纪人 | 新增 `listing_histories` | 是 |
| `Listed` | `suspended` | 业主通知暂缓 | 经纪人 | 写跟进日志 | 是 |
| `Listed` | `sold` | 本司录入成交 | 经纪人 | 自动结束挂牌历史 | 否 |
| `Listed` | `sold_elsewhere`/`rented_elsewhere` | 核实他司已成交 | 经纪人 | | 否 |
| `Listed` | `unlisted` | 强制下架 | 管理员 | | 是 |
**来源章节**: `DATA_MODEL_PROPERTY.md` §3
---
## 5. 客户/房源等级 (Grade)
**实体**: `client.clients` / `property.properties` | **字段**: `grade`
**参考**: `DATA_MODEL_CLIENT.md` §3.1 | `DATA_MODEL_PROPERTY.md` §4.1
### 状态枚举值
(domain: `client.grade` / `property.grade`)
- `A`: A (急迫)
- `B`: B (较强)
- `C`: C (一般)
- `D`: D (较弱)
- `E`: E (暂不关注) - 仅客源
### 状态迁移表
| 当前状态 | 下一状态 | 触发动作/事件 | 触发角色 | 副作用 | 是否可逆 |
| ---- | ------------------- | ------- | ---- | ----------------------------- | ---- |
| 任意状态 | `A`/`B`/`C`/`D`/`E` | 手动调整等级 | 经纪人 | 写 `status_log` / `follow_log` | 是 |
**来源章节**: `DATA_MODEL_CLIENT.md` §4, `DATA_MODEL_PROPERTY.md` §3
---
## 6. 账号状态机 (Account)
**实体**: `login.user_accounts` | **字段**: `status`
**参考**: `DATA_MODEL_LOGIN.md` §5.1
```mermaid
stateDiagram-v2
[*] --> active: 创建(初始密码)
active --> locked: 密码错误≥5次
locked --> active: 30min到期/手动解锁
active --> disabled: 离职/手动停用
disabled --> active: 复职/手动恢复
```
### 状态枚举值
(domain: `login.user_account.status`)
- `active`: 启用
- `disabled`: 停用
- `locked`: 锁定
### 状态迁移表
| 当前状态 | 下一状态 | 触发动作/事件 | 触发角色 | 副作用 | 是否可逆 |
|---|---|---|---|---|---|
| `active` | `locked` | 密码连续错误5次 | System | 设置 `locked_until` | 是 |
| `locked` | `active` | 时间到期/管理员解锁 | System/Admin | | 是 |
| `active` | `disabled` | 员工离职/手动停用 | Admin/System | 踢出所有 Session | 是 |
**来源章节**: `DATA_MODEL_LOGIN.md` §5.1
---
## 7. 升级事件状态机 (Upgrade Event)
**实体**: `public.upgrade_events` | **字段**: `status`
**参考**: `DATA_MODEL_PUBLIC.md` §4.2
```mermaid
stateDiagram-v2
[*] --> draft
draft --> pre_check: 提交
pre_check --> pre_backup: 健康检查通过
pre_backup --> batch_running: 备份完成
batch_running --> batch_done: 批次租户成功
batch_done --> batch_running: 下一批次
batch_done --> succeeded: 全部完成
batch_running --> halted: 失败/门控拦截
halted --> batch_running: 人工继续
halted --> rollback_running: 人工回滚
rollback_running --> rolled_back: 回滚完成
batch_running --> failed: 严重故障
```
### 状态枚举值
(domain: `public.upgrade_event.status`)
- `draft`: 草稿
- `pre_check`: 预检查
- `pre_backup`: 预备份
- `batch_running`: 批次执行中
- `batch_done`: 批次完成
- `halted`: 已暂停
- `succeeded`: 已成功
- `failed`: 失败
- `rollback_running`: 回滚中
- `rolled_back`: 已回滚
**来源章节**: `DATA_MODEL_PUBLIC.md` §4.2
---
## 8. 其他辅助状态
### 8.1 备份/导出任务 (Backup/Export)
**字段**: `status` | **参考**: `ENUMS.md` §2.3
- `pending` -> `in_progress` -> `success` / `failed`
### 8.2 客户端发布 (Client Release)
**字段**: `status` | **参考**: `ENUMS.md` §2.4
- `draft` -> `published` -> `archived`
- **约束**: 同平台架构下仅允许一个 `published`
### 8.3 员工状态 (Staff)
**字段**: `status` | **参考**: `DATA_MODEL_ORG.md` §4
- `probation` -> `active` -> `resigned`
- `active` <-> `frozen`
### 8.4 审批流 (Approval)
**实体**: `number_holder_approvals` | **字段**: `status`
- `pending` -> `approved` / `rejected`
---
## X. 状态机一致性校验清单
1. **枚举同步**: 状态字段值是否在 `ENUMS.md` 中定义且拼写一致?
2. **日志完备**: 每次 `status` 变更是否伴随对应的 `status_log` 插入动作?
3. **并发控制**: 状态变更是否包含 `version` 乐观锁检查?
4. **终态拦截**: 业务逻辑是否显式禁止从终态(如 `sold`, `deleted`, `rolled_back`)向外迁移?
5. **副作用触发**: 状态变更相关的异步任务(如转公客通知、缓存清理)是否已在 Service 层注册?
---
## 待澄清问题
1. **Client Invalid 恢复路径**: `DATA_MODEL_CLIENT.md` §4 提到“需经理审批后可恢复”,但未定义恢复后的目标状态(是恢复到 `suspended` 还是之前的活跃态?)。
- *涉及文件*: `DATA_MODEL_CLIENT.md`
2. **Property Unlisted 属性**: 房源在 `unlisted` 状态下,其 `attribute` (公/私盘) 是否有意义?若从 `private` 挂牌变为 `unlisted`,再次挂牌时是否应默认保留 `private` 属性?
- *涉及文件*: `DATA_MODEL_PROPERTY.md`
3. **Tenant Deleted 物理性**: `DATA_MODEL_PUBLIC.md` §4.1 提到“硬删除直接到 deleted”但在 §2.1 又说“硬删除直接物理删除行”。需要明确 `deleted` 状态是代表软删除的终点还是物理删除前的标记。
- *涉及文件*: `DATA_MODEL_PUBLIC.md`
4. **Staff Resigned 恢复**: 离职员工复职(`rejoin`)后,其 `status` 是回到 `probation` 还是 `active`
- *涉及文件*: `DATA_MODEL_ORG.md`