Sync: expand data model and gitops notes
This commit is contained in:
@@ -70,7 +70,59 @@
|
||||
|
||||
---
|
||||
|
||||
## 二、公共 Schema(Shared / Public)
|
||||
## 二、领域概览(Domain Overview)
|
||||
|
||||
本节用业务语言描述系统的核心领域对象及其关系,作为各子模块数据模型的导读。
|
||||
|
||||
### 核心领域对象
|
||||
|
||||
| 领域对象 | 表/子文档 | 业务说明 |
|
||||
|----------|-----------|----------|
|
||||
| **Tenant(租户)** | `public.tenants` | 每家房产经纪公司对应一个租户,数据完全隔离(Schema-per-Tenant) |
|
||||
| **OrgUnit(组织架构)** | `org_units` → [DATA_MODEL_ORG.md](./DATA_MODEL_ORG.md) | 树形组织架构(总部/区域/城市/大区/分公司/门店/团队/虚拟团队),物化路径存储,支持权限继承 |
|
||||
| **Staff(员工)** | `staff` → [DATA_MODEL_ORG.md](./DATA_MODEL_ORG.md) | 经纪人/店长/经理,绑定组织节点,手机号加密存储,与账号(登录)分离 |
|
||||
| **District(城区)** | `districts` → [DATA_MODEL_COMPLEX.md](./DATA_MODEL_COMPLEX.md) | 行政区划,如「静安区」,是区域体系的顶层节点 |
|
||||
| **BusinessArea(商圈)** | `business_areas` → [DATA_MODEL_COMPLEX.md](./DATA_MODEL_COMPLEX.md) | 商圈/板块,从属于城区,一个楼盘可归属多个商圈 |
|
||||
| **School(学校)** | `schools` → [DATA_MODEL_COMPLEX.md](./DATA_MODEL_COMPLEX.md) | 对口学校数据库,是买家购房决策的核心参考,与楼盘多对多关联 |
|
||||
| **Complex(楼盘/小区)** | `complexes` → [DATA_MODEL_COMPLEX.md](./DATA_MODEL_COMPLEX.md) | 房源录入的基础底座,维护楼盘标准名称/坐标/锁定状态/别名等 |
|
||||
| **Building(楼栋/单元)** | `buildings` → [DATA_MODEL_COMPLEX.md](./DATA_MODEL_COMPLEX.md) | 楼盘下的物理楼栋,区分标准结构与非标结构 |
|
||||
| **RoomUnit(房号)** | `room_units` → [DATA_MODEL_COMPLEX.md](./DATA_MODEL_COMPLEX.md) | 楼层+房间号,房源定位的最细粒度 |
|
||||
| **Property(房源)** | `properties` → §3.3 | 系统核心表,每套二手房源的完整档案,支持出售/出租/出售兼出租三态 |
|
||||
| **Client(客源)** | `clients` → [DATA_MODEL_CLIENT.md](./DATA_MODEL_CLIENT.md) | 买家/租客档案,分私客/公客/成交客,含活跃度评分与自动公客转换机制 |
|
||||
| **Viewing(带看)** | `client_viewings` → [DATA_MODEL_CLIENT.md](./DATA_MODEL_CLIENT.md) | 经纪人带客户看房的完整记录 |
|
||||
| **Match(配对)** | `client_property_matches` → [DATA_MODEL_CLIENT.md](./DATA_MODEL_CLIENT.md) | 系统/人工推荐的客源↔房源配对 |
|
||||
|
||||
### 领域关系快速导航
|
||||
|
||||
```
|
||||
District (城区)
|
||||
└─ BusinessArea (商圈)
|
||||
└─ Complex (楼盘) ─── School (对口学校)
|
||||
├─ Building (楼栋)
|
||||
│ └─ RoomUnit (房号)
|
||||
└─ Property (房源)
|
||||
├─ PropertyContact (联系人/委托方)
|
||||
├─ FollowLog (跟进日志)
|
||||
├─ Viewing (带看记录) ──── Client (客源)
|
||||
└─ Match (配对记录) ──────┘
|
||||
|
||||
OrgUnit (组织架构)
|
||||
└─ Staff (员工/经纪人) ─── Property / Client / Viewing / Match
|
||||
```
|
||||
|
||||
### 子文档索引
|
||||
|
||||
| 子文档 | 覆盖模块 | 状态 |
|
||||
|--------|----------|------|
|
||||
| [DATA_MODEL_ORG.md](./DATA_MODEL_ORG.md) | 组织人事(org_units, staff, 异动/奖惩/教育/家庭等) | ✅ 完成 |
|
||||
| [DATA_MODEL_COMPLEX.md](./DATA_MODEL_COMPLEX.md) | 楼盘/区域(districts, business_areas, complexes, buildings, room_units, schools 等) | ✅ 完成 |
|
||||
| [DATA_MODEL_CLIENT.md](./DATA_MODEL_CLIENT.md) | 客源管理(clients, requirements, follow_logs, viewings, matches 等) | ✅ 完成 |
|
||||
| 本文档 §3.3–§3.16 | 房源核心(properties 及配套 12 张表)、系统设置 | ✅ 完成 |
|
||||
|
||||
---
|
||||
|
||||
## 三、公共 Schema(Shared / Public)
|
||||
|
||||
|
||||
```sql
|
||||
-- ============================================================
|
||||
@@ -107,7 +159,7 @@ CREATE INDEX idx_domains_primary ON public.domains(tenant_id) WHERE is_primary =
|
||||
|
||||
---
|
||||
|
||||
## 三、租户 Schema(Tenant Schema)
|
||||
## 四、租户 Schema(Tenant Schema)
|
||||
|
||||
以下所有表均在每个租户的独立 Schema 内创建。
|
||||
|
||||
@@ -115,190 +167,56 @@ CREATE INDEX idx_domains_primary ON public.domains(tenant_id) WHERE is_primary =
|
||||
|
||||
### 3.1 组织人事模块(Organization & HR)
|
||||
|
||||
```sql
|
||||
-- ============================================================
|
||||
-- 组织架构:公司 → 区域 → 门店 → 组
|
||||
-- ============================================================
|
||||
> **详细模型** → 见 [`DATA_MODEL_ORG.md`](./DATA_MODEL_ORG.md)
|
||||
> 该文件为权威定义,包含完整字段、枚举、查询模式和禁止操作。
|
||||
|
||||
-- 组织节点表(树形结构,支持无限层级)
|
||||
CREATE TABLE org_units (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(100) NOT NULL,
|
||||
type VARCHAR(20) NOT NULL
|
||||
CHECK (type IN ('company','region','store','group')),
|
||||
parent_id UUID REFERENCES org_units(id) ON DELETE RESTRICT,
|
||||
path TEXT NOT NULL, -- 物化路径:/root_id/parent_id/self_id/
|
||||
depth SMALLINT NOT NULL DEFAULT 0,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ
|
||||
);
|
||||
**核心表概览**(开发时以 DATA_MODEL_ORG.md 为准):
|
||||
|
||||
CREATE INDEX idx_org_units_parent ON org_units(parent_id) WHERE deleted_at IS NULL;
|
||||
CREATE INDEX idx_org_units_path ON org_units USING gist(path gist_trgm_ops);
|
||||
-- 注:gist_trgm_ops 需要 pg_trgm 扩展,用于路径前缀查询
|
||||
| 表名 | 说明 |
|
||||
|------|------|
|
||||
| `org_units` | 组织树节点(公司/事业部/大区/区域/片区/门店/店组/职能),物化路径树 |
|
||||
| `staff` | 员工主表,含加密手机号、角色、在职状态、Django auth 绑定 |
|
||||
| `staff_personal_info` | 员工个人信息扩展(证件、学历、婚育等,1:1) |
|
||||
| `staff_transfer_logs` | 人事异动不可变审计日志(入职/调动/离职/复职等) |
|
||||
| `staff_reward_punish` | 奖惩记录 |
|
||||
| `staff_work_experiences` | 工作经历 |
|
||||
| `staff_educations` | 教育经历 |
|
||||
| `staff_trainings` | 培训经历 |
|
||||
| `staff_family_members` | 家庭成员 |
|
||||
| `staff_accounts` | 第三方平台账号绑定(58安居客/中国网络经纪人等) |
|
||||
|
||||
-- 员工表
|
||||
CREATE TABLE staff (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
org_unit_id UUID NOT NULL REFERENCES org_units(id) ON DELETE RESTRICT,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
phone_hash VARCHAR(64), -- SHA-256 哈希,用于唯一性校验
|
||||
phone_enc BYTEA, -- AES-256-GCM 加密后的手机号
|
||||
email VARCHAR(255),
|
||||
role VARCHAR(30) NOT NULL
|
||||
CHECK (role IN ('agent','store_manager','admin','operator','system')),
|
||||
job_title VARCHAR(100), -- 职务描述
|
||||
avatar_key TEXT, -- R2/S3 存储路径
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
joined_at DATE,
|
||||
left_at DATE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ,
|
||||
|
||||
-- 关联 Django auth user(用于登录认证)
|
||||
user_id INTEGER UNIQUE -- FK to django auth_user
|
||||
);
|
||||
|
||||
CREATE INDEX idx_staff_org ON staff(org_unit_id) WHERE deleted_at IS NULL;
|
||||
CREATE INDEX idx_staff_role ON staff(role) WHERE deleted_at IS NULL;
|
||||
CREATE UNIQUE INDEX idx_staff_phone_hash ON staff(phone_hash) WHERE deleted_at IS NULL;
|
||||
```
|
||||
**关键约束提示**:
|
||||
- `staff.phone_enc` AES-256-GCM 加密,`staff.phone_hash` SHA-256 用于唯一索引
|
||||
- `staff_transfer_logs` **无 deleted_at**,不可删除
|
||||
- `org_units` 路径查询:`WHERE path LIKE '/root/{target_id}/%'`
|
||||
- 员工离职:`status = 'resigned'` + `deleted_at` 软删除,记录永久保留
|
||||
|
||||
---
|
||||
|
||||
### 3.2 区域与楼盘模块(Region & Complex Management)
|
||||
|
||||
```sql
|
||||
-- ============================================================
|
||||
-- 行政区 → 商圈 → 楼盘/小区 → 楼栋
|
||||
-- 注:楼盘数据是房源录入的基础底座,数据质量直接影响房源录入效率
|
||||
-- ============================================================
|
||||
> **详细模型** → 见 [`DATA_MODEL_COMPLEX.md`](./DATA_MODEL_COMPLEX.md)
|
||||
> 本节仅作概览,开发时以 DATA_MODEL_COMPLEX.md 为权威定义。
|
||||
|
||||
-- 城市/行政区
|
||||
CREATE TABLE districts (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(50) NOT NULL,
|
||||
city VARCHAR(50) NOT NULL DEFAULT '',
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE
|
||||
);
|
||||
**核心表概览**(开发时以 DATA_MODEL_COMPLEX.md 为准):
|
||||
|
||||
-- 商圈/板块
|
||||
CREATE TABLE business_areas (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
district_id UUID NOT NULL REFERENCES districts(id) ON DELETE RESTRICT,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_business_areas_district ON business_areas(district_id);
|
||||
|
||||
-- 地铁线路
|
||||
CREATE TABLE metro_lines (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(50) NOT NULL,
|
||||
color VARCHAR(7) -- 线路颜色 HEX
|
||||
);
|
||||
|
||||
-- 地铁站
|
||||
CREATE TABLE metro_stations (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
metro_line_id UUID NOT NULL REFERENCES metro_lines(id) ON DELETE CASCADE,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
sort_order INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
-- 学校
|
||||
CREATE TABLE schools (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
district_id UUID REFERENCES districts(id) ON DELETE SET NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
type VARCHAR(20) -- 小学/初中/高中/九年一贯制 等
|
||||
);
|
||||
|
||||
CREATE INDEX idx_schools_district ON schools(district_id);
|
||||
|
||||
-- 楼盘/小区(核心基础表)
|
||||
CREATE TABLE complexes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(200) NOT NULL,
|
||||
alias VARCHAR(200), -- 别名/曾用名
|
||||
district_id UUID REFERENCES districts(id) ON DELETE SET NULL,
|
||||
business_area_id UUID REFERENCES business_areas(id) ON DELETE SET NULL,
|
||||
address VARCHAR(500),
|
||||
latitude NUMERIC(10,7),
|
||||
longitude NUMERIC(10,7),
|
||||
|
||||
-- 楼盘物理属性
|
||||
developer VARCHAR(200), -- 开发商
|
||||
property_company VARCHAR(200), -- 物业公司
|
||||
property_fee NUMERIC(8,2), -- 物业费 元/㎡/月
|
||||
green_rate NUMERIC(5,2), -- 绿化率 %
|
||||
plot_ratio NUMERIC(5,2), -- 容积率
|
||||
built_year SMALLINT, -- 竣工年份
|
||||
ownership_years VARCHAR(20), -- 产权年限枚举
|
||||
|
||||
-- 配套信息
|
||||
has_elevator BOOLEAN,
|
||||
parking_info TEXT, -- 车位情况描述
|
||||
|
||||
-- 全文检索向量(定期更新)
|
||||
search_vector TSVECTOR,
|
||||
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ,
|
||||
created_by UUID REFERENCES staff(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_complexes_district ON complexes(district_id) WHERE deleted_at IS NULL;
|
||||
CREATE INDEX idx_complexes_name_trgm ON complexes USING gin(name gin_trgm_ops);
|
||||
CREATE INDEX idx_complexes_search ON complexes USING gin(search_vector);
|
||||
CREATE INDEX idx_complexes_geo ON complexes(latitude, longitude) WHERE deleted_at IS NULL;
|
||||
|
||||
-- 楼盘与商圈多对多(一个楼盘可跨多个商圈)
|
||||
CREATE TABLE complex_business_areas (
|
||||
complex_id UUID NOT NULL REFERENCES complexes(id) ON DELETE CASCADE,
|
||||
business_area_id UUID NOT NULL REFERENCES business_areas(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (complex_id, business_area_id)
|
||||
);
|
||||
|
||||
-- 楼盘与学校关联
|
||||
CREATE TABLE complex_schools (
|
||||
complex_id UUID NOT NULL REFERENCES complexes(id) ON DELETE CASCADE,
|
||||
school_id UUID NOT NULL REFERENCES schools(id) ON DELETE CASCADE,
|
||||
school_zone VARCHAR(50), -- 学区情况:对口/参考等
|
||||
PRIMARY KEY (complex_id, school_id)
|
||||
);
|
||||
|
||||
-- 楼盘与地铁站关联
|
||||
CREATE TABLE complex_metro_stations (
|
||||
complex_id UUID NOT NULL REFERENCES complexes(id) ON DELETE CASCADE,
|
||||
station_id UUID NOT NULL REFERENCES metro_stations(id) ON DELETE CASCADE,
|
||||
distance_meters INTEGER, -- 步行距离(米)
|
||||
PRIMARY KEY (complex_id, station_id)
|
||||
);
|
||||
|
||||
-- 楼栋
|
||||
CREATE TABLE buildings (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
complex_id UUID NOT NULL REFERENCES complexes(id) ON DELETE CASCADE,
|
||||
name VARCHAR(50) NOT NULL, -- 楼栋名,如"1号楼"
|
||||
total_floors SMALLINT NOT NULL,
|
||||
has_elevator BOOLEAN,
|
||||
building_type VARCHAR(30), -- 楼型:板楼/塔楼/板塔结合
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_buildings_complex ON buildings(complex_id);
|
||||
```
|
||||
| 表名 | 说明 | 关键字段 |
|
||||
|------|------|----------|
|
||||
| `districts` | 城区/行政区 | `city`, `name`, `short_name`, `sort_order` |
|
||||
| `business_areas` | 商圈/板块(从属于城区) | `district_id`, `name`, `latitude`, `longitude` |
|
||||
| `metro_lines` | 地铁线路 | `city`, `name`, `color` |
|
||||
| `metro_stations` | 地铁站点 | `metro_line_id`, `name`, `latitude`, `longitude` |
|
||||
| `schools` | 学校(对口学区) | `district_id`, `name`, `type`, `nature`, `level` |
|
||||
| `complexes` | 楼盘/小区(房源底座) | `name`, `district_id`, `address`, `latitude/longitude`, `lock_*`, `search_vector` |
|
||||
| `complex_aliases` | 楼盘别名(含系统别名/用户自定义别名) | `complex_id`, `alias`, `is_system` |
|
||||
| `complex_business_areas` | 楼盘↔商圈多对多(含主商圈标识) | `complex_id`, `business_area_id`, `is_primary` |
|
||||
| `complex_schools` | 楼盘↔学校关联(含学区类型) | `complex_id`, `school_id`, `zone_type` |
|
||||
| `complex_metro_stations` | 楼盘↔地铁站关联(含步行距离) | `complex_id`, `station_id`, `distance_meters` |
|
||||
| `buildings` | 楼栋/单元 | `complex_id`, `name`, `is_standard`, `total_floors` |
|
||||
| `room_units` | 房号/结构单元(楼层+房间号) | `building_id`, `floor`, `room_no`, `is_standard` |
|
||||
| `complex_photos` | 楼盘照片(楼盘图/户型图/VR) | `complex_id`, `category`, `file_key`, `is_cover` |
|
||||
| `complex_attachments` | 楼盘附件 | `complex_id`, `file_key`, `file_name` |
|
||||
| `complex_price_trends` | 楼盘价格走势(月度) | `complex_id`, `record_month`, `avg_unit_price` |
|
||||
|
||||
---
|
||||
|
||||
@@ -1066,123 +984,30 @@ CREATE TABLE property_completeness (
|
||||
|
||||
### 3.17 客源管理(Client Management)
|
||||
|
||||
```sql
|
||||
-- ============================================================
|
||||
-- 客源:私客为核心,公客/成交客为后续版本
|
||||
-- ============================================================
|
||||
> **详细模型** → 见 [`DATA_MODEL_CLIENT.md`](./DATA_MODEL_CLIENT.md)
|
||||
> 该文件为权威定义,包含完整字段、枚举、状态机、查询模式和禁止操作。
|
||||
|
||||
CREATE TABLE clients (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
**核心表概览**(开发时以 DATA_MODEL_CLIENT.md 为准):
|
||||
|
||||
client_type VARCHAR(20) NOT NULL DEFAULT 'private'
|
||||
CHECK (client_type IN ('private','public','transacted')),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active'
|
||||
CHECK (status IN ('active','converted_public',
|
||||
'transacted','invalid')),
|
||||
| 表名 | 说明 |
|
||||
|------|------|
|
||||
| `clients` | 客源主表(私客/公客/成交客),含加密手机号哈希、活跃度、归属人 |
|
||||
| `client_contacts` | 联系人(1:N),手机号加密+哈希,支持多联系人 |
|
||||
| `client_requirements` | 需求信息(可多类型:二手/新房/租房),含预算/面积/商圈/朝向等偏好 |
|
||||
| `client_follow_logs` | 跟进日志(高写入频率,5种类型,敏感查看类型不可删) |
|
||||
| `client_follow_log_attachments` | 跟进附件(图片/录音,最大20MB) |
|
||||
| `client_viewings` | 带看/预约记录(1:N,含陪看人/合作带看人) |
|
||||
| `client_property_matches` | 智能配房结果(录客配房/系统配房,匹配度评分) |
|
||||
| `client_status_logs` | 状态变更不可变审计日志(改状态/改等级/转公/转成交/转无效等) |
|
||||
| `client_favorite_folders` | 私客收藏夹(经纪人自定义分组) |
|
||||
| `client_folder_items` | 收藏夹与客源的多对多关联 |
|
||||
| `client_school_preferences` | 意向学校(拆表,支持精确查询) |
|
||||
|
||||
name VARCHAR(50) NOT NULL,
|
||||
gender VARCHAR(10)
|
||||
CHECK (gender IN ('male','female','unknown')),
|
||||
|
||||
-- 手机号加密存储
|
||||
phone_enc BYTEA NOT NULL,
|
||||
phone_hash VARCHAR(64) NOT NULL,
|
||||
phone2_enc BYTEA,
|
||||
phone2_hash VARCHAR(64),
|
||||
|
||||
-- 购房需求
|
||||
purpose VARCHAR(10) NOT NULL
|
||||
CHECK (purpose IN ('buy','rent')),
|
||||
budget_min NUMERIC(12,2),
|
||||
budget_max NUMERIC(12,2),
|
||||
area_min NUMERIC(8,2),
|
||||
area_max NUMERIC(8,2),
|
||||
bedroom_needs SMALLINT[], -- 可接受的卧室数量数组
|
||||
|
||||
-- 意向区域(存 district/business_area ID 数组)
|
||||
district_ids UUID[],
|
||||
business_area_ids UUID[],
|
||||
|
||||
-- 活跃度分层(由系统计算)
|
||||
activity_level VARCHAR(10)
|
||||
CHECK (activity_level IN ('hot','warm','cold','frozen')),
|
||||
last_active_at TIMESTAMPTZ,
|
||||
|
||||
-- 负责经纪人
|
||||
agent_id UUID REFERENCES staff(id) ON DELETE SET NULL,
|
||||
org_unit_id UUID REFERENCES org_units(id) ON DELETE SET NULL,
|
||||
|
||||
source VARCHAR(50),
|
||||
remarks TEXT,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ,
|
||||
created_by UUID REFERENCES staff(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_clients_agent ON clients(agent_id) WHERE deleted_at IS NULL;
|
||||
CREATE INDEX idx_clients_phone_hash ON clients(phone_hash) WHERE deleted_at IS NULL;
|
||||
CREATE INDEX idx_clients_status ON clients(status, client_type) WHERE deleted_at IS NULL;
|
||||
CREATE INDEX idx_clients_activity ON clients(activity_level, last_active_at DESC)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
-- 客源跟进日志(复用结构,单独表避免与房源日志混合)
|
||||
CREATE TABLE client_follow_logs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
|
||||
purpose VARCHAR(50),
|
||||
content TEXT,
|
||||
log_tag VARCHAR(50),
|
||||
is_public BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
operator_id UUID REFERENCES staff(id) ON DELETE SET NULL,
|
||||
operator_snapshot JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE INDEX idx_client_logs_client ON client_follow_logs(client_id, created_at DESC)
|
||||
WHERE deleted_at IS NULL;
|
||||
|
||||
-- 智能配房记录(客源 ↔ 房源 匹配)
|
||||
CREATE TABLE client_property_matches (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
|
||||
property_id UUID NOT NULL REFERENCES properties(id) ON DELETE CASCADE,
|
||||
match_score NUMERIC(5,2), -- 匹配度评分
|
||||
match_reason JSONB, -- 匹配原因详情
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'suggested'
|
||||
CHECK (status IN ('suggested','shared','viewing','rejected')),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES staff(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_client_property_match
|
||||
ON client_property_matches(client_id, property_id);
|
||||
|
||||
-- 带看记录
|
||||
CREATE TABLE viewings (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
property_id UUID NOT NULL REFERENCES properties(id) ON DELETE RESTRICT,
|
||||
client_id UUID NOT NULL REFERENCES clients(id) ON DELETE RESTRICT,
|
||||
agent_id UUID REFERENCES staff(id) ON DELETE SET NULL,
|
||||
|
||||
viewing_type VARCHAR(20) NOT NULL DEFAULT 'first'
|
||||
CHECK (viewing_type IN ('first','revisit','empty','interview')),
|
||||
-- first=带看, revisit=复看, empty=空看, interview=面访
|
||||
|
||||
scheduled_at TIMESTAMPTZ,
|
||||
completed_at TIMESTAMPTZ,
|
||||
result VARCHAR(20)
|
||||
CHECK (result IN ('interested','not_interested',
|
||||
'negotiating','cancelled')),
|
||||
remarks TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_viewings_property ON viewings(property_id);
|
||||
CREATE INDEX idx_viewings_client ON viewings(client_id);
|
||||
```
|
||||
**关键约束提示**:
|
||||
- `client_contacts.phone_hash` 是重复客源检测的唯一依据,录入前必须查重
|
||||
- `client_status_logs` **无 deleted_at**,不可删除
|
||||
- 私客超时(配置天数内无跟进)→ Celery 自动转公(`transfer_to_public_type = 'auto'`)
|
||||
- 活跃度 `activity_level` 由 Celery 每日凌晨批量计算,不实时更新
|
||||
|
||||
---
|
||||
|
||||
@@ -1290,7 +1115,7 @@ CREATE INDEX idx_number_holder_approvals_status ON number_holder_approvals(statu
|
||||
|
||||
---
|
||||
|
||||
## 四、关键索引汇总与查询优化策略
|
||||
## 五、关键索引汇总与查询优化策略
|
||||
|
||||
### 4.1 房源列表页核心查询分析
|
||||
|
||||
@@ -1372,7 +1197,7 @@ CREATE TRIGGER trg_update_last_followed
|
||||
|
||||
---
|
||||
|
||||
## 五、Redis 缓存策略
|
||||
## 六、Redis 缓存策略
|
||||
|
||||
### 5.1 缓存 Key 规范
|
||||
|
||||
@@ -1422,7 +1247,7 @@ CREATE TRIGGER trg_update_last_followed
|
||||
|
||||
---
|
||||
|
||||
## 六、Django Model 层设计要点
|
||||
## 七、Django Model 层设计要点
|
||||
|
||||
### 6.1 抽象基类
|
||||
|
||||
@@ -1500,7 +1325,7 @@ class PropertyManager(ActiveManager):
|
||||
|
||||
---
|
||||
|
||||
## 七、数据量与性能预测
|
||||
## 八、数据量与性能预测
|
||||
|
||||
| 表名 | 预估行数 | 增长速度 | 分区策略 |
|
||||
|------|---------|---------|---------|
|
||||
@@ -1514,7 +1339,7 @@ class PropertyManager(ActiveManager):
|
||||
|
||||
---
|
||||
|
||||
## 八、必须在开发启动前明确的数据架构决策
|
||||
## 九、必须在开发启动前明确的数据架构决策
|
||||
|
||||
| 决策项 | 推荐方案 | 风险 |
|
||||
|-------|---------|------|
|
||||
|
||||
Reference in New Issue
Block a user