diff --git a/Project/fonrey/DATA_MODEL/DATA_MODEL_CLIENT.md b/Project/fonrey/DATA_MODEL/DATA_MODEL_CLIENT.md index 486c0fcc..70a020da 100644 --- a/Project/fonrey/DATA_MODEL/DATA_MODEL_CLIENT.md +++ b/Project/fonrey/DATA_MODEL/DATA_MODEL_CLIENT.md @@ -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); diff --git a/Project/fonrey/DATA_MODEL/DATA_MODEL_COMPLEX.md b/Project/fonrey/DATA_MODEL/DATA_MODEL_COMPLEX.md index 783c55dc..ee3109a6 100644 --- a/Project/fonrey/DATA_MODEL/DATA_MODEL_COMPLEX.md +++ b/Project/fonrey/DATA_MODEL/DATA_MODEL_COMPLEX.md @@ -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); diff --git a/Project/fonrey/DATA_MODEL/DATA_MODEL_ORG.md b/Project/fonrey/DATA_MODEL/DATA_MODEL_ORG.md index 48fe13d8..3d733db2 100644 --- a/Project/fonrey/DATA_MODEL/DATA_MODEL_ORG.md +++ b/Project/fonrey/DATA_MODEL/DATA_MODEL_ORG.md @@ -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() | 记录创建时间(系统自动) | --- diff --git a/Project/fonrey/DATA_MODEL/DATA_MODEL_PERMISSION.md b/Project/fonrey/DATA_MODEL/DATA_MODEL_PERMISSION.md index 857c43a3..03362e37 100644 --- a/Project/fonrey/DATA_MODEL/DATA_MODEL_PERMISSION.md +++ b/Project/fonrey/DATA_MODEL/DATA_MODEL_PERMISSION.md @@ -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": }`,如 `{"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 | — | — | 审计日志**不可删除** | **关键索引**: diff --git a/raw/Home Office/WSL2 中 Docker 容器访问宿主机代理.md b/raw/Home Office/WSL2 中 Docker 容器访问宿主机代理.md new file mode 100644 index 00000000..b005da48 --- /dev/null +++ b/raw/Home Office/WSL2 中 Docker 容器访问宿主机代理.md @@ -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 ` + +注意事项 + +- 代理软件(Clash 等)需开启「允许局域网连接」 +- 端口号按实际代理端口调整,Clash 默认 `7890` +- `host.docker.internal` 在 Docker Desktop(Windows/Mac)及 WSL2 环境下均可用 +- 避免在 Dockerfile 中硬编码 `ENV HTTPS_PROXY=http://127.0.0.1:...`,容器内无法访问 \ No newline at end of file