Files
nexus/Project/fonrey/DATA_MODEL/ENUMS.md
2026-04-28 16:39:52 +08:00

781 lines
20 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.
> **For AI assistants**: Read this entire file before writing any code. All decisions here are final. Do not suggest alternatives unless asked.
# Fonrey — 统一枚举字典ENUMS
> **定位**:本文件是 Fonrey 全局枚举标准Public + Tenant的统一实现基线。
> **版本**v2.2
> **日期**2026-04-28
> **适用范围**`DATA_MODEL_PUBLIC.md`、`DATA_MODEL_LOGIN.md`、`DATA_MODEL_ORG.md`、`DATA_MODEL_COMPLEX.md`、`DATA_MODEL_PROPERTY.md`、`DATA_MODEL_CLIENT.md`、`DATA_MODEL_PERMISSION.md`、`DATA_MODEL_SETTING.md`
> **⚠️ 枚举值命名规范**:所有枚举值统一使用 **`lower_snake_case`**(全小写+下划线)。
> 历史遗留大写值(`SUCCESS`/`FAILED`、`BOOLEAN`/`SCOPE`/`INTEGER`、`REPLACE`/`RESTRICT`/`GRANT`、`A_urgent`/`A_app`/`B_schema`/`C_feature`)在 v2.2 中已统一迁移为小写。
> **DB `CHECK` 约束、`enum_labels` 种子数据、前端代码须同步更新为新值**;迁移脚本须包含历史数据 UPDATE。
---
## 一、枚举分层标准(必须遵守)
Fonrey 采用两层枚举体系:
1. **固定枚举Fixed Enum**
- 值域固定,受 `CHECK` 或强业务约束保护
- 作为系统契约,不能随意改值
- 可落地到 `public.enum_labels`(用于统一标签)
2. **可配置枚举Configurable Enum**
- 值域由租户自行维护
- 存储在 Tenant Schema`lookup_groups` + `lookup_items`
- **禁止**对业务表字段加固定 `CHECK IN (...)`
---
## 二、全局固定枚举Public / 平台级)
### 2.1 tenant 生命周期
**domain**: `public.tenant.plan`
- `basic`:基础版
- `professional`:专业版
- `enterprise`:企业版
**domain**: `public.tenant.status`
- `creating`:创建中
- `active`:正常
- `suspended`:已挂起
- `pending_delete`:待删除
- `deleted`:已删除
- `failed`:创建/初始化失败
**domain**: `public.tenant.suspended_reason`
- `overdue`:欠费
- `violation`:违规
- `requested`:客户申请
- `other`:其他
### 2.2 平台管理员
**domain**: `public.platform_admin.role`
- `super_admin`:超级管理员
- `ops_operator`:运营管理员
- `read_only_auditor`:只读审计员
### 2.3 平台审计与备份导出
**domain**: `public.platform_audit.result`
- `success`:成功
- `failed`:失败
**domain**: `public.backup_schedule.frequency`
- `hourly`:每小时
- `daily`:每日
- `weekly`:每周
**domain**: `public.backup_schedule.storage_target`
- `local`:本地存储
- `s3`Amazon S3
- `r2`Cloudflare R2
- `gcs`Google Cloud Storage
**domain**: `public.backup_record.trigger_type`
- `auto`:自动触发
- `manual`:手动触发
- `pre_upgrade`:升级前触发
- `pre_restore`:恢复前触发
**domain**: `public.backup_record.status`
- `pending`:待执行
- `in_progress`:执行中
- `success`:成功
- `failed`:失败
**domain**: `public.export_task.format`
- `csv`CSV
- `json`JSON
- `sql_dump`SQL 导出
**domain**: `public.export_task.status`
- `pending`:待执行
- `in_progress`:执行中
- `success`:成功(语义等价原 `done`,与 `backup_record.status` 对齐)
- `failed`:失败
### 2.4 升级与发布Public
**domain**: `public.upgrade_event.event_type`
- `upgrade`:升级
- `rollback`:回滚
**domain**: `public.upgrade_event.upgrade_type`
- `app`A类-应用升级(原 `A_app`
- `schema`B类-数据库结构升级(原 `B_schema`
- `feature`C类-功能开关升级(原 `C_feature`
**domain**: `public.upgrade_event.strategy`
- `full`:全量发布
- `canary`:灰度发布
**domain**: `public.upgrade_event.status`
- `draft`:草稿
- `pre_check`:预检查
- `pre_backup`:预备份
- `batch_running`:批次执行中
- `batch_done`:批次完成
- `halted`:已暂停
- `succeeded`:已成功
- `failed`:失败
- `rollback_running`:回滚中
- `rolled_back`:已回滚
**domain**: `public.upgrade_event.failure_policy`
- `halt_batch`:失败即停止批次
- `continue`:失败继续
**domain**: `public.client_release.platform`
- `win32`Windows 客户端
**domain**: `public.client_release.arch`
- `x64`x64 架构
- `arm64`ARM64 架构
**domain**: `public.client_release.release_type`
- `normal`:普通更新
- `force`:强制更新
**domain**: `public.client_release.status`
- `draft`:草稿
- `published`:已发布
- `archived`:已归档
---
## 三、Tenant 固定枚举(模块级,值域统一)
> 说明:以下字段在 Tenant Schema 中存储,但值域为系统统一标准,属于“全局实现标准”。
## 3.1 登录认证account/login
**domain**: `login.user_account.status`
- `active`:启用
- `disabled`:停用
- `locked`:锁定
**domain**: `login.login_attempt.failure_reason`
- `wrong_password`:用户名或密码错误
- `wrong_captcha`:验证码错误
- `account_locked`:账号锁定
- `account_disabled`:账号停用
- `tenant_not_found`:租户不存在
---
## 3.2 组织人事org
**domain**: `org.org_unit.type`
- `company`:公司
- `division`:事业部
- `region`:大区
- `area`:区域
- `district`:片区
- `store`:门店
- `group`:店组
- `functional`:职能部门
**domain**: `org.org_unit.attribute`
- `direct`:直营
- `franchise`:加盟
**domain**: `org.staff.role`
- `agent`:经纪人
- `store_manager`:店长
- `area_manager`:区域经理
- `admin`:系统管理员
- `operator`:运营/行政
- `system`:系统账号
**domain**: `org.staff.status`
- `active`:在职
- `probation`:试用
- `resigned`:离职
- `frozen`:冻结
**domain**: `org.staff_personal_info.gender`
- `male`:男
- `female`:女
- `unknown`:未知
**domain**: `org.staff_personal_info.id_type`
- `id_card`:身份证
- `passport`:护照
- `other`:其他
**domain**: `org.staff_transfer.transfer_type`
- `onboard`:入职
- `transfer`:调动
- `resign`:离职
- `rejoin`:复职
- `supervisor_change`:上级变更
- `role_change`:角色变更
- `freeze`:冻结账号
- `unfreeze`:恢复账号
**domain**: `org.staff_account.platform`
- `fonrey`:房睿主账号
- `58anjuke`58安居客
- `cnreic`:中国网络经纪人
- `wechat_mp`:微信公众号
---
## 3.3 权限系统permission
**domain**: `permission.module`
- `home`:首页
- `property`:房源
- `new_house`:新房
- `client`:客源
- `transaction`:交易
- `data`:数据
- `marketing`:营销
- `hr`人事OA
- `contract`:合同
- `trinet`:三网
- `system`:系统
- `mobile`:移动端
- `smart_store`:智能门店
- `recharge`:在线充值
**domain**: `permission.value_type`
- `boolean`:开关型(原 `BOOLEAN`
- `scope`:范围型(原 `SCOPE`
- `integer`:数值型(原 `INTEGER`
**domain**: `permission.role_category`
- `agent`:置业顾问
- `store_manager`:店管
- `director`:总经
- `operator`:运营/行政
- `custom`:自定义
**domain**: `permission.scope_level`
- `none`:无
- `self`:本人
- `group`:本组
- `store`:本门店
- `area`:本区域
- `region`:本大区
- `company`:全公司
**domain**: `permission.override_mode`
- `replace`:覆盖(原 `REPLACE`
- `restrict`:限制(原 `RESTRICT`
- `grant`:授予(原 `GRANT`
**domain**: `permission.data_scope_type`
- `self`:本人
- `group`:本组
- `store`:本门店
- `area`:本区域
- `region`:本大区
- `company`:全公司
- `custom_unit`:自定义组织单元
**domain**: `permission.change_log.target_type`
- `role`:角色
- `role_permission`:角色权限
- `staff_role`:员工角色
- `staff_override`:员工权限覆盖
- `staff_scope`:员工数据范围
**domain**: `permission.change_log.action`
- `create`:创建
- `update`:更新
- `delete`:删除
- `assign`:分配
- `revoke`:撤销
---
## 3.4 楼盘区域complex
**domain**: `complex.school.type`
- `primary`:小学
- `middle`:初中
- `high`:高中
- `k9`:九年一贯制
- `k12`:十二年一贯制
**domain**: `complex.school.nature`
- `public`:公立
- `private`:私立
- `international`:国际
**domain**: `complex.school.level`
- `normal`:普通
- `key`:重点
- `top`:名校
**domain**: `complex.building_type`
- `slab`:板楼
- `tower`:塔楼
- `slab_tower`:板塔结合
**domain**: `complex.water_type`
- `civil`:民水
- `commercial`:商水
**domain**: `complex.electricity_type`
- `civil`:民电
- `commercial`:商电
**domain**: `complex.school_zone_type`
- `guaranteed`:对口
- `reference`:参考
- `lottery`:摇号
**domain**: `complex.photo.category`
- `complex`:楼盘图
- `layout`:户型图
- `vr`VR图
- `other`:其他
---
## 3.5 房源property
**domain**: `property.property_type`
- `residential`:住宅
- `villa`:别墅
- `commercial_residential`:商住
- `shop`:商铺
- `office`:写字楼
- `other`:其他
**domain**: `property.status`
- `for_sale`:出售
- `for_rent`:出租
- `for_sale_rent`:租售
- `suspended`:暂缓
- `sold_elsewhere`:他售
- `rented_elsewhere`:他租
- `sold`:成交
- `unlisted`:未挂牌
**domain**: `property.attribute`
- `public`:公盘
- `private`:私盘
- `special`:特盘
- `sealed`:封盘
**domain**: `property.orientation`
- `east`:东
- `south`:南
- `west`:西
- `north`:北
- `southeast`:东南
- `northeast`:东北
- `east_west`:东西
- `south_north`:南北
- `northwest`:西北
- `southwest`:西南
**domain**: `property.decoration`
- `rough`:毛坯
- `plain`:清水
- `simple`:简装
- `medium`:中装
- `fine`:精装
- `luxury`:豪装
**domain**: `property.house_status`
- `owner_occupied`:业主自住
- `vacant`:空置
- `tenant_occupied`:租客在住
- `unknown`:未知
**domain**: `property.viewing_time`
- `anytime`:随时看房
- `by_appointment`:预约看房
- `inconvenient`:不便看房
**domain**: `property.grade`
- `a`A急迫
- `b`B较强
- `c`C一般
- `d`D较弱
**domain**: `property.contact.gender`
- `male`:先生
- `female`:女士
**domain**: `property.contact.identity`
- `owner`:业主
- `contact`:联系人
- `subletter`:转租人
- `tenant`:租客
- `agent`:代理人
- `corporate`:企业法人
**domain**: `property.listing_history.listing_type`
- `for_sale`:出售挂牌
- `for_rent`:出租挂牌
**domain**: `property.listing_history.status`
- `active`:生效中
- `ended`:已结束
**domain**: `property.follow_log.log_type`
- `written`:手写跟进
- `modified`:修改跟进
- `sensitive_op`:敏感操作
- `sensitive_view`:敏感查看
- `other`:其他
- `system`:系统
**domain**: `property.follow_log.ai_tag`
- `ai_for_sale`AI判断可售
- `ai_not_for_sale`AI判断不可售
**domain**: `property.follow_attachment.file_type`
- `bmp`BMP
- `jpg`JPG
- `png`PNG
- `svg`SVG
- `gif`GIF
**domain**: `property.key.key_type`
- `mechanical`:机械钥匙
- `password`:密码钥匙
**domain**: `property.commission.owner_type`
- `owner`:产权人本人
- `authorized_third`:授权第三方
**domain**: `property.commission.status`
- `active`:有效
- `expired`:过期
- `cancelled`:取消
**domain**: `property.commission_attachment.category`
- `id_card`:身份证件
- `property_cert`:产权证明
- `commission_letter`:委托书
- `other`:其他
**domain**: `property.field_survey.status`
- `draft`:草稿
- `submitted`:已提交
**domain**: `property.survey_photo.category`
- `layout`:户型图
- `living_room`:客厅
- `dining_room`:餐厅
- `bedroom`:卧室
- `bathroom`:卫生间
- `kitchen`:厨房
- `entrance`:入户
- `balcony`:阳台
- `study`:书房
- `indoor_other`:室内其他
- `outdoor`:室外
**domain**: `property.photo.category`
- `cover`:封面
- `entrance`:入户
- `living_room`:客厅
- `dining_room`:餐厅
- `bedroom`:卧室
- `bathroom`:卫生间
- `kitchen`:厨房
- `balcony`:阳台
- `study`:书房
- `indoor_other`:室内其他
- `outdoor`:室外
- `panorama`:全景
**domain**: `property.attachment.category`
- `id_card`:身份证件
- `property_cert`:产权证明
- `commission_letter`:委托书
- `other`:其他
**domain**: `property.number_holder_approval.status`
- `pending`:待审批
- `approved`:已通过
- `rejected`:已驳回
---
## 3.6 客源client
**domain**: `client.client_type`
- `private`:私客
- `public`:公客
- `transacted`:成交客
**domain**: `client.status`
- `buying`:求购
- `renting`:求租
- `buy_or_rent`:租购
- `suspended`:暂缓
- `bought`:已购
- `rented_done`:已租
- `public`:公客
- `invalid`:无效
> **⚠️ 合法组合约束**`client_type` × `client.status`
> `client_type` 表示客源的"身份类别"`status` 表示客源的"当前业务状态",两者是不同维度。
> 合法组合矩阵如下:
>
> | `client_type` | 允许的 `status` 值 | 禁止的 `status` 值 |
> |---|---|---|
> | `private`(私客) | `buying` / `renting` / `buy_or_rent` / `suspended` / `invalid` | `public`、`bought`、`rented_done`(未成交不可用终态) |
> | `public`(公客) | `public` / `buying` / `renting` / `buy_or_rent` / `suspended` / `invalid` | `bought`、`rented_done` |
> | `transacted`(成交客) | `bought` / `rented_done` | 其他所有值(终态不可逆) |
>
> **实施要求**
> - 服务层(`ClientService`)在状态变更时必须校验组合合法性
> - DB 侧可用触发器或 `CHECK` 约束覆盖最关键禁止项(如 `transacted` + 非终态)
> - `private → public` 转换须调用专用方法 `transfer_to_public()`,同时修改 `client_type` 和 `status`
**domain**: `client.grade`
- `A`A急迫
- `B`B较强
- `C`C一般
- `D`D较弱
- `E`E暂不关注
**domain**: `client.property_usage`
- `residential`:住宅
- `villa`:别墅
- `commercial_residential`:商住
- `shop`:商铺
- `office`:写字楼
- `other`:其他
**domain**: `client.buying_purpose`
- `rigid`:刚需
- `investment`:投资
- `school_district`:学区
- `upgrade`:改善
- `commercial`:商用
- `other`:其他
**domain**: `client.payment_method`
- `full`:全额
- `mortgage`:商业贷款
- `mortgage_fund`:商贷+公积金
- `fund`:公积金
**domain**: `client.properties_owned`
- `none`:无
- `local_none`:本地无/外地有
- `local_has`:本地有
**domain**: `client.id_type`
- `id_card`:身份证
- `passport`:护照
- `hk_macao`:港澳通行证
- `other`:其他
**domain**: `client.transfer_to_public_type`
- `manual`:手动转公
- `auto`:自动转公
- `marketing_jump`:营销客跳公
- `resource_public`:资料客素公
**domain**: `client.invalid_reason`
- `invalid_phone`:号码无效
- `peer_agent`:同行
- `ad`:广告推销
- `no_intent`:无意向
- `other`:其他
**domain**: `client.transacted_type`
- `bought`:我购
- `rented`:我租
**domain**: `client.transacted_property_type`
- `second_hand`:二手
- `new_house`:新房
**domain**: `client.activity_level`
- `new_matched`:新配对
- `active_7d`7日活跃
- `active_30d`30日活跃
- `active_90d`90日活跃
- `expiring`:即将过期
- `frozen`:暂缓中
- `invalid`:无效
**domain**: `client.contact.gender`
- `male`:先生
- `female`:女士
**domain**: `client.requirement_type`
- `second_hand`:二手
- `new_house`:新房
- `rental`:租房
**domain**: `client.floor_preference`
- `no_first`:不要一楼
- `low`:低楼层
- `mid`:中楼层
- `high`:高楼层
- `no_top`:不要顶楼
**domain**: `client.orientation`
- `east`:东
- `south`:南
- `west`:西
- `north`:北
**domain**: `client.decoration`
- `rough`:毛坯
- `plain`:清水
- `simple`:简装
- `medium`:中装
- `fine`:精装
- `luxury`:豪装
**domain**: `client.building_age_range`
- `within_5y`5年内
- `5_10y`5-10年
- `10_15y`10-15年
- `15_20y`15-20年
- `over_20y`20年以上
**domain**: `client.follow_log.log_type`
- `written`:写入跟进
- `modified`:修改跟进
- `sensitive_view`:敏感查看
- `other`:其他
- `system`:系统
**domain**: `client.viewing.viewing_type`
- `appointment`:预约
- `viewing`:带看
- `revisit`:复看
- `empty`:空看
**domain**: `client.viewing.client_intent`
- `interested`:感兴趣
- `not_interested`:不感兴趣
- `negotiating`:谈判中
- `cancelled`:取消
**domain**: `client.property_match.match_source`
- `recorded`:录客配房
- `system`:系统配房
**domain**: `client.property_match.match_group`
- `quality_layout`:优质户型
- `price_reduced`:降价
- `hot`:热门
- `newly_listed`:新上
**domain**: `client.property_match.status`
- `suggested`:待推送
- `shared`:已分享
- `rejected`:已反馈不合适
- `viewed`:客户已查看
**domain**: `client.status_log.change_type`
- `status_change`:改状态
- `grade_change`:改等级
- `to_public`:转公客
- `to_transacted`:转成交
- `to_invalid`:转无效
- `owner_change`:改归属人
- `source_change`:改来源
- `merge`:合并客源
---
## 3.7 系统配置setting
**domain**: `setting.tenant_setting.value_type`
- `bool`:布尔
- `int`:整数
- `string`:字符串
- `enum`:枚举
**domain**: `setting.field_rule.module`
- `property`:房源
- `client`:客源(预留)
**domain**: `setting.field_rule.entity_type`(与 `property.property_type` 对齐)
- `residential`:住宅
- `villa`:别墅
- `commercial_residential`:商住
- `shop`:商铺
- `office`:写字楼
- `other`:其他
**domain**: `setting.field_rule.trade_status`
- `sale`:出售
- `rent`:出租
- `sale_rent`:租售
- `all`:全部(原设计为 `*`,因 SQL/URL/权限表达式通配误解风险已统一改为 `all`DB CHECK 约束、前端筛选器须同步)
**domain**: `setting.field_rule.requirement`
- `required`:必填
- `optional`:选填
- `hidden`:隐藏
---
## 四、Tenant 可配置枚举字段清单lookup_items 权威)
> 以下字段值域由 `lookup_items` 维护,属于租户级配置,不在业务表中写死 `CHECK`。
| domain统一命名 | 对应字段 | 当前状态 | 说明 |
|---|---|---|---|
| `client.source` | `clients.source` | ✅ 已落地 | 客源来源 |
| `client.follow_purpose` | `client_follow_logs.purpose` | ✅ 已落地 | 客源跟进目的 |
| `property.source` | `properties.source` | ✅ 已落地 | 房源来源 |
| `property.follow_purpose` | `follow_logs.purpose` | 🔄 建议统一 | 房源跟进目的(建议与 `client.follow_purpose` 共享或独立分组) |
| `property.commission_type` | `commissions.commission_type` | 🔄 待入组 | 委托类型(独家/非独家等) |
| `client.match_feedback` | `client_property_matches.feedback` | 🔄 待入组 | 配房反馈原因 |
| `org.reward_punish_category` | `staff_reward_punish.category` | 🔄 待入组 | 人事奖惩类别 |
### 4.1 lookup_groups 规范Tenant Schema
- `module`: 业务模块标识(如 `client` / `property` / `org`
- `key`: 领域键(如 `source` / `follow_purpose`
- 同一组内 `value` 不可重复(`UNIQUE(group_id, value)`
- `is_system = TRUE` 的项禁止物理删除(仅可停用)
---
## 五、统一实现约束
1. **固定枚举值不可改名**:只能新增或停用,禁止修改既有 value。
2. **中文展示从字典取值**:前端/UI 不得硬编码中文。
3. **可配置枚举不得加固定 CHECK**:防止租户自定义被数据库约束阻断。
4. **跨模块同名枚举必须复用语义**:如 `status` 在不同领域必须使用 domain 区分,不允许混用。
5. **缓存规范**
- 固定枚举:`public:enum_labels:{domain}`(建议 TTL 24h
- 可配置枚举:`{schema}:setting:lookup:{module}.{key}`TTL 300s
---
## 六、变更流程(必须同步)
新增或修改任一枚举时,必须同时更新:
1. 本文档 `ENUMS.md`
2. 对应 `DATA_MODEL_*.md` 字段定义CHECK / 注释 / 业务规则)
3. `enum_labels` 种子数据(若为固定枚举)或 `lookup_groups/items` fixture若为可配置枚举
4. 服务层缓存失效逻辑Redis key
---
## 七、与 ADR 的一致性说明
本文件已对齐以下冻结决策:
- 固定枚举与可配置枚举双轨并存
- 状态机和值域以文档为权威来源
- Tenant 级可配置枚举统一由 `setting` 模块托管
- Agent 编码前先读枚举标准,禁止各模块自行定义“影子枚举”