data model注释补全

This commit is contained in:
Shen Wei
2026-04-30 06:57:02 +08:00
parent eada3af824
commit 91fc0b06d6
5 changed files with 216 additions and 172 deletions

View File

@@ -66,7 +66,7 @@ Staff (员工)
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| client_no | VARCHAR(30) | UNIQUE, NOT NULL | 系统生成的客源编号,格式由运营配置(如 KY20260424001 |
| client_type | VARCHAR(20) | NOT NULL DEFAULT 'private' | `private`=私客 / `public`=公客 / `transacted`=成交客 |
| status | VARCHAR(20) | NOT NULL DEFAULT 'buying' | 见下方枚举 |
@@ -102,11 +102,11 @@ Staff (员工)
| last_follow_at | TIMESTAMPTZ | | 最后跟进时间(冗余,列表排序用) |
| commission_date | DATE | | 委托日期 |
| entrust_count | SMALLINT | NOT NULL DEFAULT 1 | 委托次数(成交后再委托则累加) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| deleted_at | TIMESTAMPTZ | | 软删除 |
| created_by | UUID | FK→staff, SET NULL | |
| updated_by | UUID | FK→staff, SET NULL | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
| deleted_at | TIMESTAMPTZ | | 软删除时间戳NULL=未删除非NULL=已软删除 |
| created_by | UUID | FK→staff, SET NULL | 创建人(操作员工) |
| updated_by | UUID | FK→staff, SET NULL | 最后修改人(操作员工) |
| version | INTEGER | NOT NULL DEFAULT 1 | 乐观锁版本号;每次 UPDATE +1应用层检测 0 行受影响时抛 ConflictError |
**关键索引**
@@ -127,8 +127,8 @@ CREATE INDEX idx_clients_last_follow ON clients(last_follow_at DESC NULLS LAST)
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| client_id | UUID | NOT NULL, FK→clients, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| client_id | UUID | NOT NULL, FK→clients, CASCADE | 所属客源(关联 clients 表,联系人随客源级联删除) |
| sort_order | SMALLINT | NOT NULL DEFAULT 0 | 联系人1为主联系人sort_order=0 |
| name | VARCHAR(50) | NOT NULL | 联系人姓名 |
| gender | VARCHAR(10) | NOT NULL DEFAULT 'male' | `male`=先生 / `female`=女士 |
@@ -137,14 +137,14 @@ CREATE INDEX idx_clients_last_follow ON clients(last_follow_at DESC NULLS LAST)
| phone_country_code | VARCHAR(10) | NOT NULL DEFAULT '+86' | 国际区号 |
| phone_is_invalid | BOOLEAN | NOT NULL DEFAULT FALSE | 是否被标记为无效号码 |
| phone2_enc | BYTEA | | 备用电话2 |
| phone2_hash | VARCHAR(64) | | |
| phone2_hash | VARCHAR(64) | | 备用电话2哈希SHA-256用于重复检测 |
| wechat | VARCHAR(100) | | 微信号 |
| qq | VARCHAR(20) | | QQ号 |
| remarks | VARCHAR(200) | | 联系人备注最多200字 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| deleted_at | TIMESTAMPTZ | | 软删除(不影响客源本身) |
| created_by | UUID | FK→staff, SET NULL | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
| deleted_at | TIMESTAMPTZ | | 软删除时间戳NULL=未删除(不影响客源本身) |
| created_by | UUID | FK→staff, SET NULL | 创建人(操作员工) |
**关键索引**
```sql
@@ -167,8 +167,8 @@ CREATE INDEX idx_client_contacts_client ON client_contacts(client_id) WHERE dele
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| client_id | UUID | NOT NULL, FK→clients, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| client_id | UUID | NOT NULL, FK→clients, CASCADE | 所属客源(关联 clients 表,需求随客源级联删除) |
| requirement_type | VARCHAR(20) | NOT NULL | `second_hand`=二手 / `new_house`=新房 / `rental`=租房 |
| is_primary | BOOLEAN | NOT NULL DEFAULT TRUE | 是否为主需求(用于列表展示) |
| budget_min | NUMERIC(12,2) | | 最低预算(万元/元,依据需求类型) |
@@ -188,8 +188,8 @@ CREATE INDEX idx_client_contacts_client ON client_contacts(client_id) WHERE dele
| school_enrollment_date | DATE | | 入学时间月份精度取该月1日存储 |
| traffic_preference | TEXT | | 交通备注 |
| requirement_notes | VARCHAR(200) | | 需求备注最多200字 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
**关键索引**
```sql
@@ -208,8 +208,8 @@ CREATE INDEX idx_client_requirements_area ON client_requirements(area_min, area_
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| client_id | UUID | NOT NULL, FK→clients, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| client_id | UUID | NOT NULL, FK→clients, CASCADE | 所属客源(关联 clients 表,跟进日志随客源级联删除) |
| log_type | VARCHAR(30) | NOT NULL | 见下方枚举 |
| purpose | VARCHAR(50) | | 跟进目的lookup_items 维护23项 |
| content | TEXT | | 跟进内容最少6字最多500字 |
@@ -219,8 +219,8 @@ CREATE INDEX idx_client_requirements_area ON client_requirements(area_min, area_
| is_deletable | BOOLEAN | NOT NULL DEFAULT TRUE | 敏感信息查看类型为 FALSE不可删除 |
| operator_id | UUID | FK→staff, SET NULL | 操作人 |
| operator_snapshot | JSONB | | `{name, store_group, role}`(防止人员调动后显示异常) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| deleted_at | TIMESTAMPTZ | | 仅 is_deletable=TRUE 时可软删 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| deleted_at | TIMESTAMPTZ | | 软删除时间戳;仅 is_deletable=TRUE 时可软删 |
**log_type 枚举**
```
@@ -246,15 +246,15 @@ CREATE INDEX idx_client_follow_sensitive ON client_follow_logs(client_id, create
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| follow_log_id | UUID | NOT NULL, FK→client_follow_logs, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| follow_log_id | UUID | NOT NULL, FK→client_follow_logs, CASCADE | 所属跟进日志(附件随日志级联删除) |
| file_key | TEXT | NOT NULL | R2/S3 存储路径 |
| file_name | VARCHAR(255) | NOT NULL | |
| file_name | VARCHAR(255) | NOT NULL | 原始文件名(用于展示和下载) |
| file_size | INTEGER | NOT NULL | bytes最大 20MB |
| file_type | VARCHAR(10) | CHECK | `bmp`/`jpg`/`png`/`gif` |
| has_location | BOOLEAN | NOT NULL DEFAULT FALSE | 是否含 GPS 位置信息 |
| sort_order | SMALLINT | NOT NULL DEFAULT 0 | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| sort_order | SMALLINT | NOT NULL DEFAULT 0 | 附件排序顺序 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
---
@@ -262,9 +262,9 @@ CREATE INDEX idx_client_follow_sensitive ON client_follow_logs(client_id, create
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| client_id | UUID | NOT NULL, FK→clients, RESTRICT | |
| property_id | UUID | NOT NULL, FK→properties, RESTRICT | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| client_id | UUID | NOT NULL, FK→clients, RESTRICT | 所属客源(带看记录仅软删除,不随客源删除) |
| property_id | UUID | NOT NULL, FK→properties, RESTRICT | 带看房源(房源删除时保留带看记录) |
| viewing_type | VARCHAR(20) | NOT NULL DEFAULT 'viewing' | `appointment`=预约 / `viewing`=带看 / `revisit`=复看 / `empty`=空看 |
| agent_id | UUID | FK→staff, SET NULL | 主带看经纪人 |
| companion_ids | UUID[] | | 陪看人员 ID 数组最多5人 |
@@ -275,9 +275,9 @@ CREATE INDEX idx_client_follow_sensitive ON client_follow_logs(client_id, create
| situation | TEXT | | 带看情况必填≥6字 |
| client_intent | VARCHAR(20) | | 客户意向:`interested`=感兴趣 / `not_interested`=不感兴趣 / `negotiating`=谈判中 / `cancelled`=取消 |
| viewing_progress | SMALLINT | | 带看进度1=一看2=二看...,冗余字段,触发器维护) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| deleted_at | TIMESTAMPTZ | | |
| created_by | UUID | FK→staff, SET NULL | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| deleted_at | TIMESTAMPTZ | | 软删除时间戳;带看记录可软删除 |
| created_by | UUID | FK→staff, SET NULL | 创建人(操作员工) |
**关键索引**
```sql
@@ -292,9 +292,9 @@ CREATE INDEX idx_client_viewings_agent ON client_viewings(agent_id) WHERE delete
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| client_id | UUID | NOT NULL, FK→clients, CASCADE | |
| property_id | UUID | NOT NULL, FK→properties, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| client_id | UUID | NOT NULL, FK→clients, CASCADE | 所属客源 |
| property_id | UUID | NOT NULL, FK→properties, CASCADE | 匹配的房源 |
| match_source | VARCHAR(20) | NOT NULL DEFAULT 'recorded' | `recorded`=录客配房(基于录入需求) / `system`=系统配房(算法推荐) |
| match_group | VARCHAR(30) | | 分组:`quality_layout`=优质户型 / `price_reduced`=降价 / `hot`=热门 / `newly_listed`=新上 |
| match_score | NUMERIC(5,2) | | 匹配度评分0-100 |
@@ -303,7 +303,7 @@ CREATE INDEX idx_client_viewings_agent ON client_viewings(agent_id) WHERE delete
| shared_at | TIMESTAMPTZ | | 分享时间 |
| feedback | VARCHAR(50) | | 反馈原因lookup_items 维护) |
| calculated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 配房计算时间 |
| created_by | UUID | FK→staff, SET NULL | |
| created_by | UUID | FK→staff, SET NULL | 触发配房操作的员工录客配房时记录系统配房可为NULL |
**关键索引**
```sql
@@ -318,14 +318,14 @@ CREATE INDEX idx_client_matches_status ON client_property_matches(client_id, sta
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| client_id | UUID | NOT NULL, FK→clients, RESTRICT | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| client_id | UUID | NOT NULL, FK→clients, RESTRICT | 所属客源状态日志永久保留RESTRICT 防止删除客源) |
| change_type | VARCHAR(30) | NOT NULL | `status_change`=改状态 / `grade_change`=改等级 / `to_public`=转公客 / `to_transacted`=转成交 / `to_invalid`=转无效 / `owner_change`=改归属人 / `source_change`=改来源 |
| old_value | JSONB | | 变更前快照,格式:`{"status": "buying", "label": "求购"}` |
| new_value | JSONB | | 变更后快照 |
| reason | TEXT | | 变更理由改状态必填最多200字 |
| operator_id | UUID | NOT NULL, FK→staff, RESTRICT | |
| operated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| operator_id | UUID | NOT NULL, FK→staff, RESTRICT | 操作人(必填,状态变更审计用) |
| operated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 操作时间(系统自动记录) |
| ⚠️ 无 deleted_at | — | — | 此表记录**不可删除** |
**关键索引**
@@ -340,13 +340,13 @@ CREATE INDEX idx_client_status_logs_type ON client_status_logs(change_type, oper
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| staff_id | UUID | NOT NULL, FK→staff, CASCADE | 收藏夹所属经纪人 |
| name | VARCHAR(10) | NOT NULL | 收藏夹名称最多10字 |
| is_default | BOOLEAN | NOT NULL DEFAULT FALSE | 系统默认收藏夹 |
| sort_order | INTEGER | NOT NULL DEFAULT 0 | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| deleted_at | TIMESTAMPTZ | | |
| sort_order | INTEGER | NOT NULL DEFAULT 0 | 收藏夹显示顺序(升序) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| deleted_at | TIMESTAMPTZ | | 软删除时间戳NULL=未删除 |
```sql
CREATE INDEX idx_favorite_folders_staff ON client_favorite_folders(staff_id) WHERE deleted_at IS NULL;
@@ -360,10 +360,10 @@ CREATE UNIQUE INDEX idx_favorite_folders_default ON client_favorite_folders(staf
| 字段 | 类型 | 约束 | 业务说明 |
| ----------- | ---------------------- | --------------------------------------------- | ---- |
| folder_id | UUID | NOT NULL, FK→client_favorite_folders, CASCADE | |
| client_id | UUID | NOT NULL, FK→clients, CASCADE | |
| added_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| PRIMARY KEY | (folder_id, client_id) | | |
| folder_id | UUID | NOT NULL, FK→client_favorite_folders, CASCADE | 所属收藏夹 |
| client_id | UUID | NOT NULL, FK→clients, CASCADE | 被收藏的客源 |
| added_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 加入收藏夹时间 |
| PRIMARY KEY | (folder_id, client_id) | | 联合主键(同一客源在同一收藏夹只能出现一次) |
```sql
CREATE INDEX idx_folder_items_client ON client_folder_items(client_id);
@@ -377,11 +377,11 @@ CREATE INDEX idx_folder_items_client ON client_folder_items(client_id);
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| requirement_id | UUID | NOT NULL, FK→client_requirements, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| requirement_id | UUID | NOT NULL, FK→client_requirements, CASCADE | 所属需求(意向学校随需求级联删除) |
| school_id | UUID | FK→schools, SET NULL | 从学校表选择,允许为 NULL自由输入 |
| school_name | VARCHAR(100) | NOT NULL | 学校名称(当 school_id 为 NULL 时为手动输入) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
```sql
CREATE INDEX idx_school_prefs_requirement ON client_school_preferences(requirement_id);

View File

@@ -61,14 +61,14 @@ MetroLine (地铁线路)
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| city | VARCHAR(50) | NOT NULL | 所属城市(支持多城市扩展,如「上海」「北京」) |
| name | VARCHAR(50) | NOT NULL | 行政区名称,如「静安区」 |
| short_name | VARCHAR(20) | | 简称,如「静安」 |
| sort_order | INTEGER | NOT NULL DEFAULT 0 | 列表展示排序 |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | FALSE=已停用(不在筛选项中展示) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
```sql
CREATE UNIQUE INDEX idx_districts_city_name ON districts(city, name) WHERE is_active = TRUE;
@@ -80,15 +80,15 @@ CREATE UNIQUE INDEX idx_districts_city_name ON districts(city, name) WHERE is_ac
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| district_id | UUID | NOT NULL, FK→districts, RESTRICT | 所属城区 |
| name | VARCHAR(100) | NOT NULL | 商圈名称 |
| sort_order | INTEGER | NOT NULL DEFAULT 0 | |
| sort_order | INTEGER | NOT NULL DEFAULT 0 | 列表展示排序 |
| latitude | NUMERIC(10,7) | | 商圈中心坐标(纬度) |
| longitude | NUMERIC(10,7) | | 商圈中心坐标(经度) |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | FALSE=已停用(不在筛选项中展示) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
```sql
CREATE INDEX idx_business_areas_district ON business_areas(district_id) WHERE is_active = TRUE;
@@ -101,12 +101,12 @@ CREATE UNIQUE INDEX idx_business_areas_name ON business_areas(district_id, name)
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| city | VARCHAR(50) | NOT NULL | 所属城市 |
| name | VARCHAR(50) | NOT NULL | 线路名如「1号线」 |
| color | VARCHAR(7) | | 线路颜色 HEX`#E3002B` |
| sort_order | INTEGER | NOT NULL DEFAULT 0 | |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | |
| sort_order | INTEGER | NOT NULL DEFAULT 0 | 列表展示排序 |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | FALSE=已停用(不在筛选项中展示) |
---
@@ -114,13 +114,13 @@ CREATE UNIQUE INDEX idx_business_areas_name ON business_areas(district_id, name)
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| metro_line_id | UUID | NOT NULL, FK→metro_lines, CASCADE | 所属线路 |
| name | VARCHAR(50) | NOT NULL | 站名 |
| latitude | NUMERIC(10,7) | | 站点坐标 |
| longitude | NUMERIC(10,7) | | |
| longitude | NUMERIC(10,7) | | 站点坐标(经度) |
| sort_order | INTEGER | NOT NULL DEFAULT 0 | 沿线排序 |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | FALSE=已停用(不在筛选项中展示) |
```sql
CREATE INDEX idx_metro_stations_line ON metro_stations(metro_line_id) WHERE is_active = TRUE;
@@ -132,15 +132,15 @@ CREATE INDEX idx_metro_stations_line ON metro_stations(metro_line_id) WHERE is_a
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| district_id | UUID | FK→districts, SET NULL | 所属城区 |
| name | VARCHAR(100) | NOT NULL | 学校名称 |
| type | VARCHAR(20) | | 学校类型:`primary`=小学 / `middle`=初中 / `high`=高中 / `k9`=九年一贯制 / `k12`=十二年一贯制 |
| nature | VARCHAR(20) | | 学校性质:`public`=公立 / `private`=私立 / `international`=国际学校 |
| level | VARCHAR(20) | | 学校等级:`normal`=普通 / `key`=重点 / `top`=名校 |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | FALSE=已停用(不在筛选项中展示) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
```sql
CREATE INDEX idx_schools_district ON schools(district_id) WHERE is_active = TRUE;
@@ -153,13 +153,13 @@ CREATE INDEX idx_schools_name_trgm ON schools USING gin(name gin_trgm_ops);
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| name | VARCHAR(200) | NOT NULL | 标准楼盘名称,**不可在编辑页修改**(需走合并/申请流程) |
| district_id | UUID | FK→districts, SET NULL | 所属城区 |
| address | VARCHAR(500) | | 详细地址(不可在编辑页修改,需走纠错流程) |
| address_summary | VARCHAR(100) | | 概要地址如「海波路1000弄」可编辑 |
| latitude | NUMERIC(10,7) | | 楼盘坐标(纬度),完整度目标 ≥ 90% |
| longitude | NUMERIC(10,7) | | |
| longitude | NUMERIC(10,7) | | 地铁站经度坐标WGS84 |
| **物业属性** | | | |
| property_usage_types | VARCHAR(20)[] | | 物业类型多选:`residential`/`villa`/`commercial_residential`/`commercial`/`office`/`other` |
| building_structure | VARCHAR(30) | | 楼栋结构枚举(运营维护):`unit_room`=单元-房号 / `other`=其他 |
@@ -199,11 +199,11 @@ CREATE INDEX idx_schools_name_trgm ON schools USING gin(name gin_trgm_ops);
| search_vector | TSVECTOR | | 由触发器自动维护name + alias + address |
| **状态** | | | |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | FALSE=已停用楼盘 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| deleted_at | TIMESTAMPTZ | | 软删除 |
| created_by | UUID | FK→staff, SET NULL | |
| updated_by | UUID | FK→staff, SET NULL | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
| deleted_at | TIMESTAMPTZ | | 软删除时间戳NULL=未删除非NULL=已软删除 |
| created_by | UUID | FK→staff, SET NULL | 创建人(操作员工) |
| updated_by | UUID | FK→staff, SET NULL | 最后更新人(操作员工) |
| version | INTEGER | NOT NULL DEFAULT 1 | 乐观锁版本号;每次 UPDATE +1应用层检测 0 行受影响时抛 ConflictError |
**关键索引**
@@ -221,12 +221,12 @@ CREATE INDEX idx_complexes_active ON complexes(is_active) WHERE deleted_at IS NU
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | 所属楼盘(别名随楼盘级联删除) |
| alias | VARCHAR(200) | NOT NULL | 别名最多20字/条,多别名多行存储) |
| is_system | BOOLEAN | NOT NULL DEFAULT FALSE | TRUE=系统/标准别名只读FALSE=用户自定义 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_by | UUID | FK→staff, SET NULL | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| created_by | UUID | FK→staff, SET NULL | 创建人(操作员工) |
```sql
CREATE INDEX idx_complex_aliases_complex ON complex_aliases(complex_id);
@@ -239,10 +239,10 @@ CREATE INDEX idx_complex_aliases_alias_trgm ON complex_aliases USING gin(alias g
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | |
| business_area_id | UUID | NOT NULL, FK→business_areas, CASCADE | |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | 所属楼盘 |
| business_area_id | UUID | NOT NULL, FK→business_areas, CASCADE | 关联商圈 |
| is_primary | BOOLEAN | NOT NULL DEFAULT FALSE | 主商圈(唯一)用于列表显示 |
| PRIMARY KEY | (complex_id, business_area_id) | | |
| PRIMARY KEY | (complex_id, business_area_id) | | 联合主键(楼盘与商圈多对多) |
```sql
-- 主商圈只能有一个
@@ -255,10 +255,10 @@ CREATE UNIQUE INDEX idx_complex_biz_area_primary ON complex_business_areas(compl
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | |
| school_id | UUID | NOT NULL, FK→schools, CASCADE | |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | 所属楼盘 |
| school_id | UUID | NOT NULL, FK→schools, CASCADE | 对口学校 |
| zone_type | VARCHAR(30) | | 学区类型:`guaranteed`=对口 / `reference`=参考 / `lottery`=摇号 |
| PRIMARY KEY | (complex_id, school_id) | | |
| PRIMARY KEY | (complex_id, school_id) | | 联合主键(楼盘与学校多对多) |
```sql
CREATE INDEX idx_complex_schools_school ON complex_schools(school_id);
@@ -272,10 +272,10 @@ CREATE INDEX idx_complex_schools_school ON complex_schools(school_id);
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | |
| station_id | UUID | NOT NULL, FK→metro_stations, CASCADE | |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | 所属楼盘 |
| station_id | UUID | NOT NULL, FK→metro_stations, CASCADE | 关联地铁站 |
| distance_meters | INTEGER | | 步行距离(米) |
| PRIMARY KEY | (complex_id, station_id) | | |
| PRIMARY KEY | (complex_id, station_id) | | 联合主键(楼盘与地铁站多对多) |
```sql
CREATE INDEX idx_complex_metro_complex ON complex_metro_stations(complex_id);
@@ -288,8 +288,8 @@ CREATE INDEX idx_complex_metro_station ON complex_metro_stations(station_id);
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | 所属楼盘 |
| name | VARCHAR(50) | NOT NULL | 楼栋名如「1号楼」「A栋2单元」 |
| is_standard | BOOLEAN | NOT NULL DEFAULT FALSE | TRUE=标准结构(经运营核准) |
| property_usage_type | VARCHAR(20) | | 物业类型(可与楼盘不同,如商住楼盘内有纯商铺楼栋) |
@@ -298,10 +298,10 @@ CREATE INDEX idx_complex_metro_station ON complex_metro_stations(station_id);
| land_use_years | VARCHAR(30) | | 土地使用年限 |
| has_elevator | BOOLEAN | | 是否有电梯 |
| school_id | UUID | FK→schools, SET NULL | 关联对口学校(楼栋级别的学区差异) |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_by | UUID | FK→staff, SET NULL | |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | FALSE=已停用(楼栋被删除或合并) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
| created_by | UUID | FK→staff, SET NULL | 创建人(操作员工) |
```sql
CREATE INDEX idx_buildings_complex ON buildings(complex_id) WHERE is_active = TRUE;
@@ -314,16 +314,16 @@ CREATE UNIQUE INDEX idx_buildings_name ON buildings(complex_id, name) WHERE is_a
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| building_id | UUID | NOT NULL, FK→buildings, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| building_id | UUID | NOT NULL, FK→buildings, CASCADE | 所属楼栋 |
| floor | SMALLINT | NOT NULL | 楼层(实际层数,地下为负数) |
| floor_name | VARCHAR(20) | | 楼层名称展示如「1层」「B1层」 |
| room_no | VARCHAR(30) | NOT NULL | 房号如「01」「101」 |
| display_no | VARCHAR(50) | | 展示用完整房号如「3-1-101」 |
| is_standard | BOOLEAN | NOT NULL DEFAULT FALSE | TRUE=已归一化为标准结构 |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | FALSE=已拆除/不存在 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
```sql
CREATE INDEX idx_room_units_building ON room_units(building_id) WHERE is_active = TRUE;
@@ -336,19 +336,19 @@ CREATE UNIQUE INDEX idx_room_units_unique ON room_units(building_id, floor, room
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | 所属楼盘 |
| category | VARCHAR(20) | NOT NULL | `complex`=楼盘图 / `layout`=户型图 / `vr`=VR全景 / `other`=其他 |
| file_key | TEXT | NOT NULL | R2/S3 路径 |
| thumbnail_key | TEXT | | 缩略图路径 |
| file_name | VARCHAR(255) | | |
| file_size | INTEGER | | bytes |
| width | INTEGER | | |
| height | INTEGER | | |
| file_name | VARCHAR(255) | | 原始文件名 |
| file_size | INTEGER | | 文件大小(bytes |
| width | INTEGER | | 图片宽度px |
| height | INTEGER | | 图片高度px |
| is_cover | BOOLEAN | NOT NULL DEFAULT FALSE | 楼盘封面图 |
| sort_order | SMALLINT | NOT NULL DEFAULT 0 | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_by | UUID | FK→staff, SET NULL | |
| sort_order | SMALLINT | NOT NULL DEFAULT 0 | 同类别内的排序顺序 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| created_by | UUID | FK→staff, SET NULL | 上传人(操作员工) |
```sql
CREATE INDEX idx_complex_photos_complex ON complex_photos(complex_id);
@@ -362,15 +362,15 @@ CREATE UNIQUE INDEX idx_complex_photos_cover ON complex_photos(complex_id) WHERE
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | |
| file_key | TEXT | NOT NULL | |
| file_name | VARCHAR(255) | NOT NULL | |
| file_size | INTEGER | | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | 所属楼盘 |
| file_key | TEXT | NOT NULL | R2/S3 存储路径 |
| file_name | VARCHAR(255) | NOT NULL | 原始文件名 |
| file_size | INTEGER | | 文件大小bytes |
| file_type | VARCHAR(50) | | MIME type |
| sort_order | SMALLINT | NOT NULL DEFAULT 0 | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_by | UUID | FK→staff, SET NULL | |
| sort_order | SMALLINT | NOT NULL DEFAULT 0 | 同类别内的排序顺序 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| created_by | UUID | FK→staff, SET NULL | 上传人(操作员工) |
---
@@ -378,14 +378,14 @@ CREATE UNIQUE INDEX idx_complex_photos_cover ON complex_photos(complex_id) WHERE
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| complex_id | UUID | NOT NULL, FK→complexes, CASCADE | 所属楼盘 |
| record_month | DATE | NOT NULL | 月份统一存为该月1日如 2026-04-01 |
| avg_sale_price | NUMERIC(12,2) | | 月均售价(万元/套) |
| avg_unit_price | NUMERIC(10,2) | | 月均单价(元/m² |
| transaction_count | INTEGER | | 成交套数 |
| listing_count | INTEGER | | 当月挂牌套数 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
```sql
CREATE UNIQUE INDEX idx_complex_price_trend_month ON complex_price_trends(complex_id, record_month);

View File

@@ -52,7 +52,7 @@ OrgUnit (树形自引用,物化路径)
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| name | VARCHAR(100) | NOT NULL | 部门/组织名称 |
| type | VARCHAR(20) | NOT NULL, CHECK | 枚举:`company` / `division`(事业部) / `region`(大区) / `area`(区域) / `district`(片区) / `store`(门店) / `group`(店组) / `functional`(职能) |
| parent_id | UUID | FK→self, RESTRICT | 父节点,根节点为 NULL |
@@ -71,9 +71,9 @@ OrgUnit (树形自引用,物化路径)
| ext_start | INTEGER | | 分机号范围:起始 |
| ext_end | INTEGER | | 分机号范围:结束 |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | FALSE = 已关闭部门,仍可在筛选中显示 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| deleted_at | TIMESTAMPTZ | | 软删除 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
| deleted_at | TIMESTAMPTZ | | 软删除时间戳NULL=未删除非NULL=已软删除 |
**关键索引**
```sql
@@ -92,7 +92,7 @@ CREATE INDEX idx_org_units_type ON org_units(type) WHERE deleted_at IS NULL AND
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| org_unit_id | UUID | NOT NULL, FK→org_units | 当前所属组织节点(门店或店组) |
| user_id | INTEGER | UNIQUE, FK→auth_user | Django auth 登录账号 ID |
| name | VARCHAR(50) | NOT NULL | 真实姓名 |
@@ -125,9 +125,9 @@ CREATE INDEX idx_org_units_type ON org_units(type) WHERE deleted_at IS NULL AND
| recruit_by_id | UUID | FK→staff.id, SET NULL | 招聘人 |
| recruit_source | VARCHAR(50) | | 招聘来源 |
| referrer_id | UUID | FK→staff.id, SET NULL | 转介人 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| deleted_at | TIMESTAMPTZ | | 软删除(离职员工仍保留记录) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
| deleted_at | TIMESTAMPTZ | | 软删除时间戳;离职员工不可硬删除,保留档案 |
**关键索引**
```sql
@@ -149,7 +149,7 @@ CREATE INDEX idx_staff_status ON staff(status) WHERE deleted_at IS NULL;
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| staff_id | UUID | UNIQUE, NOT NULL, FK→staff | 1:1 关系 |
| gender | VARCHAR(10) | | `male` / `female` / `unknown` |
| id_type | VARCHAR(20) | | 证件类型:`id_card`(身份证) / `passport` / `other` |
@@ -170,8 +170,8 @@ CREATE INDEX idx_staff_status ON staff(status) WHERE deleted_at IS NULL;
| work_start_date | DATE | | 参加工作时间 |
| emergency_contact | VARCHAR(50) | | 紧急联系人 |
| emergency_phone_enc | BYTEA | | 紧急联系人电话(加密) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_by | UUID | FK→staff.id, SET NULL | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
| updated_by | UUID | FK→staff.id, SET NULL | 最后修改人(操作员工) |
---
@@ -179,16 +179,16 @@ CREATE INDEX idx_staff_status ON staff(status) WHERE deleted_at IS NULL;
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| staff_id | UUID | NOT NULL, FK→staff, RESTRICT | 被操作员工 |
| transfer_type | VARCHAR(30) | NOT NULL, CHECK | 枚举见下方 |
| old_value | JSONB | | 变动前的值快照,格式:`{"field": "org_unit_id", "value": "...", "label": "门店A"}` |
| new_value | JSONB | | 变动后的值快照 |
| transfer_date | DATE | NOT NULL | 异动生效日期(可以是过去日期) |
| remarks | VARCHAR(50) | | 备注最多50字 |
| operator_id | UUID | NOT NULL, FK→staff, RESTRICT | 操作人 |
| operator_id | UUID | NOT NULL, FK→staff, RESTRICT | 操作人(必填,异动审计必须记录) |
| operated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 系统操作时间 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动,等同 operated_at |
| ⚠️ 无 deleted_at | — | — | 异动记录**不可删除** |
**transfer_type 枚举**
@@ -216,16 +216,16 @@ CREATE INDEX idx_transfer_logs_operator ON staff_transfer_logs(operator_id);
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| staff_id | UUID | NOT NULL, FK→staff | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| staff_id | UUID | NOT NULL, FK→staff | 被奖惩员工 |
| rp_date | DATE | NOT NULL | 奖惩日期 |
| category | VARCHAR(50) | NOT NULL | 奖惩类别(枚举由 lookup 表维护) |
| name | VARCHAR(100) | NOT NULL | 奖惩名称(与类别联动) |
| remarks | TEXT | | 备注 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_by | UUID | FK→staff.id, SET NULL | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| deleted_at | TIMESTAMPTZ | | 软删除 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| created_by | UUID | FK→staff.id, SET NULL | 录入人(操作员工) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
| deleted_at | TIMESTAMPTZ | | 软删除时间戳NULL=未删除非NULL=已软删除 |
---
@@ -246,14 +246,14 @@ CREATE INDEX idx_transfer_logs_operator ON staff_transfer_logs(operator_id);
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|----------|
| id | UUID | PK | |
| staff_id | UUID | NOT NULL, FK→staff | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| staff_id | UUID | NOT NULL, FK→staff | 所属员工(必填,证件信息随员工关联) |
| platform | VARCHAR(30) | NOT NULL, CHECK | `fonrey`(主账号) / `58anjuke` / `cnreic`(中国网络经纪人) / `wechat_mp`(微信公众号) |
| account_no | VARCHAR(100) | | 账号/手机号 |
| is_real_name_match | BOOLEAN | | 实名信息一致性(中国网络经纪人专用) |
| is_bound | BOOLEAN | NOT NULL DEFAULT FALSE | 是否已绑定 |
| bound_at | TIMESTAMPTZ | | 绑定时间 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
---

View File

@@ -115,7 +115,7 @@ PermissionChangeLog (append-only) ← 所有变更流水
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|---------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| code | VARCHAR(150) | UNIQUE, NOT NULL | 权限编码,规则:`{module}.{sub_module}.{action}[.{qualifier}]`,如 `client.private.view.scope` |
| module | VARCHAR(50) | NOT NULL | 一级模块枚举(见 §4.1 |
| sub_module | VARCHAR(50) | | 二级模块(如 `二手&租赁``商圈精耕` |
@@ -132,8 +132,8 @@ PermissionChangeLog (append-only) ← 所有变更流水
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | 下线权限项置 FALSE历史记录保留 |
| is_deprecated | BOOLEAN | NOT NULL DEFAULT FALSE | 废弃标记(不再推荐使用但保持兼容) |
| version | INTEGER | NOT NULL DEFAULT 1 | 权限项定义版本,变更时递增,用于缓存失效 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
**关键索引**
```sql
@@ -153,18 +153,18 @@ CREATE INDEX idx_permission_defs_active ON permission_defs(is_active) WHERE is_a
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|---------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| name | VARCHAR(100) | NOT NULL | 角色名称 |
| category | VARCHAR(30) | NOT NULL, CHECK | `agent`(置业顾问) / `store_manager`(店管) / `director`(总经) / `operator`(运营) / `custom`(见 §4.3 |
| description | TEXT | | 角色描述 |
| template_role_id | UUID | FK→roles, SET NULL | 权限模板来源角色PRD「引用该角色配置」列 |
| is_system_builtin | BOOLEAN | NOT NULL DEFAULT FALSE | 系统内置角色(如"最大权限角色"),不可删除、不可改名 |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | |
| is_active | BOOLEAN | NOT NULL DEFAULT TRUE | 角色是否启用FALSE=禁用(员工无法继承该角色权限) |
| created_by | UUID | FK→staff, SET NULL | 创建人PRD: 角色类别只能由创建者修改) |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_by | UUID | FK→staff, SET NULL | |
| deleted_at | TIMESTAMPTZ | | 软删除 |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
| updated_by | UUID | FK→staff, SET NULL | 最后修改人(权限管理审计用) |
| deleted_at | TIMESTAMPTZ | | 软删除时间戳NULL=未删除非NULL=已软删除 |
**关键索引**
```sql
@@ -185,13 +185,13 @@ CREATE INDEX idx_roles_template ON roles(template_role_id);
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|---------|
| id | UUID | PK | |
| role_id | UUID | NOT NULL, FK→roles, CASCADE | |
| permission_def_id | UUID | NOT NULL, FK→permission_defs, RESTRICT | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| role_id | UUID | NOT NULL, FK→roles, CASCADE | 所属角色(稀疏存储:角色删除时级联清理权限值) |
| permission_def_id | UUID | NOT NULL, FK→permission_defs, RESTRICT | 权限定义RESTRICT防止删除仍被引用的权限项 |
| value | JSONB | NOT NULL | 统一格式 `{"v": <value>}`,如 `{"v": true}` / `{"v": "store"}` / `{"v": 50}` |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| updated_by | UUID | FK→staff, SET NULL | |
| created_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录创建时间(系统自动) |
| updated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 记录最后更新时间(系统自动) |
| updated_by | UUID | FK→staff, SET NULL | 最后修改人(权限审计用) |
**关键索引**
```sql
@@ -208,12 +208,12 @@ CREATE INDEX idx_role_permissions_def ON role_permissions(permission_def_id);
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|---------|
| id | UUID | PK | |
| staff_id | UUID | NOT NULL, FK→staff, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| staff_id | UUID | NOT NULL, FK→staff, CASCADE | 所属员工(员工删除时级联删除角色关联) |
| role_id | UUID | NOT NULL, FK→roles, PROTECT | 角色被员工引用时禁止删除 |
| is_primary | BOOLEAN | NOT NULL DEFAULT FALSE | 主角色标识每个员工有且仅有一个主角色Issue #5 |
| assigned_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| assigned_by | UUID | FK→staff, SET NULL | |
| assigned_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 角色分配时间(系统自动) |
| assigned_by | UUID | FK→staff, SET NULL | 分配操作人(管理员) |
| valid_from | DATE | | 生效日(预留未来"定时生效"功能) |
| valid_until | DATE | | 失效日 |
@@ -232,14 +232,14 @@ CREATE INDEX idx_staff_roles_role ON staff_roles(role_id);
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|---------|
| id | UUID | PK | |
| staff_id | UUID | NOT NULL, FK→staff, CASCADE | |
| permission_def_id | UUID | NOT NULL, FK→permission_defs, RESTRICT | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| staff_id | UUID | NOT NULL, FK→staff, CASCADE | 所属员工(员工删除时级联删除覆盖记录) |
| permission_def_id | UUID | NOT NULL, FK→permission_defs, RESTRICT | 被覆盖的权限项 |
| value | JSONB | NOT NULL | 个人权限值,同 `{"v": ...}` 格式 |
| override_mode | VARCHAR(10) | NOT NULL DEFAULT 'REPLACE' | `REPLACE`(覆盖角色合并值PRD 默认) / `RESTRICT`(限制上限) / `GRANT`(仅扩展) — Issue #6 |
| reason | TEXT | | 管理员备注(建议强制,为后续审计) |
| modified_by | UUID | FK→staff, SET NULL | |
| modified_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| modified_by | UUID | FK→staff, SET NULL | 执行个人权限修改的管理员 |
| modified_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 最近修改时间(系统自动) |
**关键索引**
```sql
@@ -257,14 +257,14 @@ CREATE INDEX idx_staff_overrides_staff ON staff_permission_overrides(staff_id);
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|---------|
| id | UUID | PK | |
| staff_id | UUID | NOT NULL, FK→staff, CASCADE | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| staff_id | UUID | NOT NULL, FK→staff, CASCADE | 所属员工(员工删除时级联删除范围记录) |
| scope_type | VARCHAR(20) | NOT NULL, CHECK | `self` / `group` / `store` / `area` / `region` / `company` / `custom_unit` |
| org_unit_id | UUID | FK→org_units, RESTRICT | `scope_type='custom_unit'` 时必填,指向具体的组织节点;其他类型时 NULL`staff.org_unit_id` 动态推导) |
| is_readable | BOOLEAN | NOT NULL DEFAULT TRUE | 可读 |
| is_writable | BOOLEAN | NOT NULL DEFAULT FALSE | 可写(默认只读) |
| granted_by | UUID | FK→staff, SET NULL | |
| granted_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| granted_by | UUID | FK→staff, SET NULL | 授权操作人(管理员) |
| granted_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 授权时间(系统自动) |
| expires_at | TIMESTAMPTZ | | 临时授权失效时间 |
| reason | TEXT | | 授予原因 |
@@ -288,7 +288,7 @@ CREATE INDEX idx_data_scopes_expires ON staff_data_scopes(expires_at) WHERE expi
| 字段 | 类型 | 约束 | 业务说明 |
|------|------|------|---------|
| id | UUID | PK | |
| id | UUID | PK | 主键(系统生成,业务无关) |
| target_type | VARCHAR(30) | NOT NULL, CHECK | `role` / `role_permission` / `staff_role` / `staff_override` / `staff_scope` |
| target_id | UUID | NOT NULL | 被变更对象的 ID上述各表的主键 |
| staff_id | UUID | FK→staff, SET NULL | 被影响员工target 是 `staff_role/staff_override/staff_scope` 时必填,便于按员工查询) |
@@ -301,7 +301,7 @@ CREATE INDEX idx_data_scopes_expires ON staff_data_scopes(expires_at) WHERE expi
| operator_ip | INET | | 操作来源 IP |
| user_agent | TEXT | | 操作终端 UA |
| reason | TEXT | | 操作原因(批量设置角色等场景强制填写) |
| operated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | |
| operated_at | TIMESTAMPTZ | NOT NULL DEFAULT NOW() | 操作时间append-only流水系统自动 |
| ⚠️ 无 deleted_at | — | — | 审计日志**不可删除** |
**关键索引**

View File

@@ -0,0 +1,44 @@
#wsl #docker #proxy
容器内的 `127.0.0.1` 指向容器自身,无法访问宿主机代理。需用 Docker 内置 DNS 名称替代。
解决方案
将 `127.0.0.1` 替换为 `host.docker.internal`Docker 会自动解析为宿主机 IP。
```
FROM python:3.12-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \
libpq-dev gcc \
&& rm -rf /var/lib/apt/lists/*
COPY requirements/base.txt requirements/base.txt
RUN pip install --no-cache-dir \
--proxy http://host.docker.internal:10808 \
--timeout 120 \
-r requirements/base.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "config.asgi:application", "--host", "0.0.0.0", "--port", "8000"]
```
其他命令同理
apt
`apt-get -o Acquire::http::Proxy="http://host.docker.internal:10808" update`
curl
`curl -x http://host.docker.internal:10808 <url>`
注意事项
- 代理软件Clash 等)需开启「允许局域网连接」
- 端口号按实际代理端口调整Clash 默认 `7890`
- `host.docker.internal` 在 Docker DesktopWindows/Mac及 WSL2 环境下均可用
- 避免在 Dockerfile 中硬编码 `ENV HTTPS_PROXY=http://127.0.0.1:...`,容器内无法访问