Files
nexus/Project/fonrey/DATA_MODEL/DATA_MODEL_COMPLEX.md
2026-04-30 20:33:51 +08:00

25 KiB
Raw Blame History

For AI assistants: Read this entire file before writing any code. All decisions here are final. Do not suggest alternatives unless asked.

Fonrey — 楼盘与区域数据模型DATA_MODEL_COMPLEX

所属系统: Fonrey 房产经纪管理系统
版本: v1.0
日期: 2026-04-24
关联模块: apps/complex/ — 楼盘/小区、楼栋、结构(楼层+房号)、区域、学校


变更历史

日期 变更人 变更内容
2026-04-30 Atlas 补充“变更历史”章节(文档治理)

一、领域概览Domain Overview

核心概念

  • Complex楼盘/小区):房源录入的基础底座。每套房源必须归属于某一楼盘。楼盘数据由运营/数据管理员集中维护,质量直接影响房源录入效率和搜索精度。
  • Building楼栋/单元)楼盘下的物理楼栋是组织房源位置的第二级。一个楼盘可有多个楼栋如「1号楼」「2栋2单元」
  • RoomUnit房号/结构单元):楼栋内特定楼层的某个房间标识,是房源定位的最细粒度。支持「标准结构」(经运营标准化)和「非标结构」(未归一化)两类。
  • District城区/行政区):行政区划,如静安区、闵行区。
  • BusinessArea商圈/板块):商圈是区域内的细分市场区域,如「南京西路商圈」,一个楼盘可跨多个商圈。
  • School学校:楼盘对口学校,是买家购房决策的核心关注点。一个楼盘可关联多所学校,一所学校可对口多个楼盘。
  • MetroLine / MetroStation地铁线路/站点):楼盘与最近地铁站的距离关系,用于通勤筛选。

关键业务规则

  1. 楼盘名称不可在编辑页修改:楼盘名称(name)变更须通过「合并楼盘」或「申请流程」处理,防止经纪人随意改名造成数据混乱。
  2. 数据锁定机制:楼盘有 4 类锁(楼栋锁/房号锁/信息锁/标准房号锁),锁定后对应数据只有管理员可解锁修改。
  3. 非标结构处理:未与标准结构关联的房号为「非标」,系统记录非标数量,引导运营逐步消除。
  4. 搜索依赖全文检索:楼盘名称、别名、地址需维护 search_vectortsvector)以支持模糊搜索和联想补全。
  5. 地理坐标优先级:楼盘坐标是区域聚合展示(地图找房)的核心数据,完整度目标 ≥ 90%。
  6. 学校关联影响房源:从楼盘详情删除对口学校,会级联删除该楼盘下所有房源的对应学区标注。

二、实体关系

District (城区/行政区)
  └── 1:N ── BusinessArea (商圈/板块)
                └── N:M ── Complex (through complex_business_areas)

Complex (楼盘)
  ├── N:M ── BusinessArea     (through complex_business_areas)
  ├── N:M ── School           (through complex_schools)
  ├── N:M ── MetroStation     (through complex_metro_stations, 附带距离)
  ├── 1:N ── Building         (楼栋/单元)
  │             └── 1:N ── RoomUnit (楼层+房号)
  ├── 1:N ── ComplexPhoto     (楼盘照片:楼盘图/户型图/VR)
  ├── 1:N ── ComplexAttachment(附件)
  ├── 1:N ── ComplexPriceTrend(价格走势,月度)
  └── 1:N ── ComplexAlias     (别名)

MetroLine (地铁线路)
  └── 1:N ── MetroStation (站点)

三、Schema 定义

3.1 districts — 城区/行政区

字段 类型 约束 业务说明
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() 记录最后更新时间(系统自动)
CREATE UNIQUE INDEX idx_districts_city_name ON districts(city, name) WHERE is_active = TRUE;

3.2 business_areas — 商圈/板块

字段 类型 约束 业务说明
id UUID PK 主键(系统生成,业务无关)
district_id UUID NOT NULL, FK→districts, RESTRICT 所属城区
name VARCHAR(100) NOT NULL 商圈名称
sort_order INTEGER NOT NULL DEFAULT 0 列表展示排序
latitude NUMERIC(10,7) 商圈中心坐标(纬度)
longitude NUMERIC(10,7) 商圈中心坐标(经度)
is_active BOOLEAN NOT NULL DEFAULT TRUE FALSE=已停用(不在筛选项中展示)
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 记录创建时间(系统自动)
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 记录最后更新时间(系统自动)
CREATE INDEX idx_business_areas_district ON business_areas(district_id) WHERE is_active = TRUE;
CREATE UNIQUE INDEX idx_business_areas_name ON business_areas(district_id, name);

3.3 metro_lines — 地铁线路

字段 类型 约束 业务说明
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 FALSE=已停用(不在筛选项中展示)

3.4 metro_stations — 地铁站点

字段 类型 约束 业务说明
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) 站点坐标(经度)
sort_order INTEGER NOT NULL DEFAULT 0 沿线排序
is_active BOOLEAN NOT NULL DEFAULT TRUE FALSE=已停用(不在筛选项中展示)
CREATE INDEX idx_metro_stations_line ON metro_stations(metro_line_id) WHERE is_active = TRUE;

3.5 schools — 学校

字段 类型 约束 业务说明
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 FALSE=已停用(不在筛选项中展示)
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 记录创建时间(系统自动)
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 记录最后更新时间(系统自动)
CREATE INDEX idx_schools_district ON schools(district_id) WHERE is_active = TRUE;
CREATE INDEX idx_schools_name_trgm ON schools USING gin(name gin_trgm_ops);

3.6 complexes — 楼盘/小区(核心基础表)

字段 类型 约束 业务说明
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) 地铁站经度坐标WGS84
物业属性
property_usage_types VARCHAR(20)[] 物业类型多选:residential/villa/commercial_residential/commercial/office/other
building_structure VARCHAR(30) 楼栋结构枚举(运营维护):unit_room=单元-房号 / other=其他
building_type VARCHAR(20) 建筑类型:slab=板楼 / tower=塔楼 / slab_tower=板塔结合
land_use_years VARCHAR(30) 土地使用年限如「70年」
built_year SMALLINT 竣工年份(可多选,存最早竣工年)
built_years SMALLINT[] 竣工年份多值(楼盘分期竣工)
ownership_category VARCHAR(30)[] 权属类别多选(运营维护枚举)
total_units INTEGER 单元总数
total_households INTEGER 总户数
建设信息
total_floor_area NUMERIC(12,2) 小区总建筑面积
plot_area NUMERIC(12,2) 小区占地面积
plot_ratio NUMERIC(5,2) 容积率
green_rate NUMERIC(5,2) 绿化率(%
developer VARCHAR(200) 开发商
物业信息
property_company VARCHAR(200) 物业公司
property_fee NUMERIC(8,2) 物业费(元/m²/月)
property_phone VARCHAR(30) 物业电话
停车
parking_total INTEGER 车位总数
parking_underground INTEGER 地下车位数
parking_ratio VARCHAR(20) 停车位配比如「100:63」
配套
water_type VARCHAR(10) civil=民水 / commercial=商水
electricity_type VARCHAR(10) civil=民电 / commercial=商电
has_central_heating BOOLEAN 是否统一供暖
has_gas BOOLEAN 是否有燃气
remarks TEXT 备注
锁定状态
lock_building BOOLEAN NOT NULL DEFAULT FALSE 楼栋锁(锁定后不可增删楼栋)
lock_room BOOLEAN NOT NULL DEFAULT FALSE 房号锁
lock_info BOOLEAN NOT NULL DEFAULT FALSE 信息锁(锁定后基本信息只读)
lock_standard_room BOOLEAN NOT NULL DEFAULT FALSE 标准房号锁
全文检索
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 软删除时间戳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

关键索引

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 AND latitude IS NOT NULL;
CREATE INDEX idx_complexes_active ON complexes(is_active) WHERE deleted_at IS NULL;

3.7 complex_aliases — 楼盘别名

字段 类型 约束 业务说明
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 创建人(操作员工)
CREATE INDEX idx_complex_aliases_complex ON complex_aliases(complex_id);
CREATE INDEX idx_complex_aliases_alias_trgm ON complex_aliases USING gin(alias gin_trgm_ops);

3.8 complex_business_areas — 楼盘与商圈多对多

字段 类型 约束 业务说明
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) 联合主键(楼盘与商圈多对多)
-- 主商圈只能有一个
CREATE UNIQUE INDEX idx_complex_biz_area_primary ON complex_business_areas(complex_id) WHERE is_primary = TRUE;

3.9 complex_schools — 楼盘与学校关联

字段 类型 约束 业务说明
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) 联合主键(楼盘与学校多对多)
CREATE INDEX idx_complex_schools_school ON complex_schools(school_id);

业务注意删除此关联记录时需同步清理对应房源的学区标注Application 层事务处理)


3.10 complex_metro_stations — 楼盘与地铁站关联

字段 类型 约束 业务说明
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) 联合主键(楼盘与地铁站多对多)
CREATE INDEX idx_complex_metro_complex ON complex_metro_stations(complex_id);
CREATE INDEX idx_complex_metro_station ON complex_metro_stations(station_id);

3.11 buildings — 楼栋/单元

字段 类型 约束 业务说明
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) 物业类型(可与楼盘不同,如商住楼盘内有纯商铺楼栋)
built_year SMALLINT 竣工年份
total_floors SMALLINT 总层数
land_use_years VARCHAR(30) 土地使用年限
has_elevator BOOLEAN 是否有电梯
school_id UUID FK→schools, 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 创建人(操作员工)
CREATE INDEX idx_buildings_complex ON buildings(complex_id) WHERE is_active = TRUE;
CREATE UNIQUE INDEX idx_buildings_name ON buildings(complex_id, name) WHERE is_active = TRUE;

3.12 room_units — 房号/结构单元(楼层+房间号)

字段 类型 约束 业务说明
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() 记录最后更新时间(系统自动)
CREATE INDEX idx_room_units_building ON room_units(building_id) WHERE is_active = TRUE;
CREATE UNIQUE INDEX idx_room_units_unique ON room_units(building_id, floor, room_no) WHERE is_active = TRUE;

3.13 complex_photos — 楼盘照片

字段 类型 约束 业务说明
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 图片宽度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 上传人(操作员工)
CREATE INDEX idx_complex_photos_complex ON complex_photos(complex_id);
CREATE INDEX idx_complex_photos_category ON complex_photos(complex_id, category);
CREATE UNIQUE INDEX idx_complex_photos_cover ON complex_photos(complex_id) WHERE is_cover = TRUE;

3.14 complex_attachments — 楼盘附件

字段 类型 约束 业务说明
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 上传人(操作员工)

字段 类型 约束 业务说明
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() 记录创建时间(系统自动)
CREATE UNIQUE INDEX idx_complex_price_trend_month ON complex_price_trends(complex_id, record_month);
CREATE INDEX idx_complex_price_trend_complex ON complex_price_trends(complex_id, record_month DESC);

四、枚举常量

complexes.building_type建筑类型

slab          = 板楼
tower         = 塔楼
slab_tower    = 板塔结合

complexes.water_type / electricity_type

civil         = 民水/民电(住宅水电费率)
commercial    = 商水/商电(商业水电费率,费用较高,影响买家决策)

complex_schools.zone_type学区类型

guaranteed    = 对口(直升)
reference     = 参考(可能入读)
lottery       = 摇号(通过摇号入学)

buildings.is_standard / room_units.is_standard

TRUE  = 已标准化(楼栋/房号已经运营核准,可用于精准房源定位)
FALSE = 非标(用户自输入,未核准,存在歧义风险)

五、查询模式

5.1 楼盘名称联想搜索(录入房源时的自动补全)

-- 使用全文检索向量,支持中文分词近似匹配
SELECT id, name, address_summary, district_id
FROM complexes
WHERE search_vector @@ plainto_tsquery('simple', :keyword)
   OR name ILIKE :keyword_prefix  -- 前缀精确匹配优先
  AND deleted_at IS NULL
  AND is_active = TRUE
ORDER BY
  ts_rank(search_vector, plainto_tsquery('simple', :keyword)) DESC,
  name
LIMIT 20;

5.2 楼盘列表(含房源数量统计)

SELECT
    c.id, c.name, c.address, c.latitude, c.longitude,
    d.name AS district_name,
    ba.name AS primary_business_area,
    COUNT(DISTINCT b.id) AS building_count,
    COUNT(DISTINCT p.id) FILTER (WHERE p.status IN ('for_sale','for_sale_rent')) AS sale_count,
    COUNT(DISTINCT p.id) FILTER (WHERE p.status IN ('for_rent','for_sale_rent')) AS rent_count
FROM complexes c
LEFT JOIN districts d ON d.id = c.district_id
LEFT JOIN complex_business_areas cba ON cba.complex_id = c.id AND cba.is_primary = TRUE
LEFT JOIN business_areas ba ON ba.id = cba.business_area_id
LEFT JOIN buildings b ON b.complex_id = c.id AND b.is_active = TRUE
LEFT JOIN properties p ON p.complex_id = c.id AND p.deleted_at IS NULL
WHERE c.deleted_at IS NULL
  AND c.district_id = ANY(:district_ids)  -- 区域筛选
GROUP BY c.id, d.name, ba.name
ORDER BY c.name
LIMIT 20 OFFSET :offset;

5.3 查询楼盘下的楼层-房号矩阵(结构管理)

-- 选中单元后,加载楼层×房号矩阵
SELECT
    ru.floor,
    ru.floor_name,
    ru.room_no,
    ru.display_no,
    ru.is_standard,
    p.id AS property_id,       -- 如果该房号已有房源,关联显示
    p.status AS property_status
FROM room_units ru
LEFT JOIN properties p ON p.building_id = ru.building_id
    AND p.room_no = ru.room_no
    AND p.floor = ru.floor
    AND p.deleted_at IS NULL
WHERE ru.building_id = :building_id
  AND ru.is_active = TRUE
ORDER BY ru.floor DESC, ru.room_no;

六、触发器

6.1 楼盘全文检索向量(含别名)

CREATE OR REPLACE FUNCTION update_complex_search_vector()
RETURNS TRIGGER AS $$
BEGIN
    NEW.search_vector :=
        setweight(to_tsvector('simple', COALESCE(NEW.name, '')), 'A') ||
        setweight(to_tsvector('simple', COALESCE(NEW.address_summary, '')), 'B') ||
        setweight(to_tsvector('simple', COALESCE(NEW.address, '')), 'C');
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_complex_search_vector
    BEFORE INSERT OR UPDATE OF name, address_summary, address
    ON complexes
    FOR EACH ROW EXECUTE FUNCTION update_complex_search_vector();

-- 别名变更时同步更新楼盘 search_vector
CREATE OR REPLACE FUNCTION update_complex_search_on_alias()
RETURNS TRIGGER AS $$
BEGIN
    UPDATE complexes
    SET search_vector = (
        setweight(to_tsvector('simple', COALESCE(name, '')), 'A') ||
        setweight(to_tsvector('simple',
            COALESCE((SELECT string_agg(alias, ' ') FROM complex_aliases WHERE complex_id = complexes.id), '')), 'B') ||
        setweight(to_tsvector('simple', COALESCE(address_summary, '')), 'C') ||
        setweight(to_tsvector('simple', COALESCE(address, '')), 'D')
    ),
    updated_at = NOW()
    WHERE id = COALESCE(NEW.complex_id, OLD.complex_id);
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_complex_alias_search
    AFTER INSERT OR UPDATE OR DELETE ON complex_aliases
    FOR EACH ROW EXECUTE FUNCTION update_complex_search_on_alias();

七、禁止操作

  • 严禁直接修改 complexes.name:楼盘名称变更必须走「楼盘合并」流程或「管理员申请」,通过 Application 层拦截任何直接 UPDATE name 字段的操作
  • 严禁硬删除 complexes 记录:有房源关联的楼盘不可删除(RESTRICT 外键),已有房源的楼盘软删除后房源仍可正常访问
  • 严禁删除 complex_schools 关联而不清理房源学区标注:必须在同一事务中清理对应 property.school_ids 数据
  • 严禁在楼盘坐标为 NULL 时将其用于地图聚合:坐标为空时不参与地图展示,过滤条件:WHERE latitude IS NOT NULL
  • 严禁在 lock_info=TRUE 时绕过 Application 层直接修改楼盘信息字段:锁定状态必须在服务层检查,不依赖数据库约束
  • 严禁在没有 deleted_at IS NULL 过滤的情况下查询 complexes:楼盘软删除过滤必须存在