> **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 编码前先读枚举标准,禁止各模块自行定义“影子枚举”