12 KiB
For AI assistants: Read this entire file before writing any code. All decisions here are final. Do not suggest alternatives unless asked.
Fonrey 楼盘管理技术方案
版本: 1.0
项目: Fonrey 房产经纪管理系统
技术栈: Django 4.x + HTMX + Alpine.js + PostgreSQL 16 + Redis + Celery + Cloudflare R2
关联 PRD: PRD/房源管理/楼盘管理模块PRD.md(v1.0)
关联数据模型: DATA_MODEL/DATA_MODEL_COMPLEX.md(本方案不重复 DDL)
关联契约规范: TECH_STACK/API_CONTRACT.md(全局 API 契约权威)
关联枚举字典: DATA_MODEL/ENUMS.md
最后更新: 2026-04-27
变更历史
| 日期 | 变更人 | 变更内容 |
|---|---|---|
| 2026-04-30 | Atlas | 补充“变更历史”章节(文档治理) |
一、文档定位与边界
本文件只定义楼盘模块的:
- 服务边界与模块协作
- API 端点设计(重点)
- HTMX 局刷协议
- 权限接入、异步任务、缓存与性能约束
- 测试与验收映射
不在本文件展开:
complexes/buildings/room_units/districts/business_areas/schools表结构、索引、触发器。以DATA_MODEL_COMPLEX.md为唯一权威来源。
二、范围定义(以 TASK.md 为准)
2.1 P0 必须覆盖
- US-COMPLEX-001:管理员录入与维护楼盘基础信息
- US-COMPLEX-002:经纪人查看楼盘列表与详情
- US-COMPLEX-003:管理员维护区域管理(城区/商圈)
2.2 P1/P2 预留(端点可预留,不在当前强制交付)
- US-COMPLEX-010:楼盘照片管理
- US-COMPLEX-011:楼盘价格走势维护
- US-COMPLEX-012:周边配套/学校管理
- US-COMPLEX-020:应用数据标准
三、模块架构边界
3.1 模块职责(apps/complex)
- 维护楼盘基础档案(楼盘、别名、商圈、学校、地铁关联)
- 维护楼栋与房号结构(供房源录入精准归位)
- 提供楼盘搜索、联想、详情聚合与区域筛选能力
- 承担区域与学校主数据管理(P0 侧重城区/商圈)
3.2 外部依赖
| 依赖模块 | 依赖内容 | 依赖方式 |
|---|---|---|
apps/property |
房源数量统计、楼盘详情联动跳转 | 只读聚合查询 |
apps/client |
客源区域筛选项复用(城区/商圈) | 读取共享主数据 |
apps/org |
操作人信息审计 | staff_id 写审计 |
apps/permission |
楼盘查看/编辑/区域维护权限校验 | PermissionChecker |
core/cache.py |
楼盘联想缓存、区域字典缓存 | Redis key 带 schema 前缀 |
Celery |
完整度重算、价格趋势重算、批量任务 | 异步任务 |
| 地图服务(后续) | 周边配套查询、坐标纠偏 | 适配器层(P1) |
3.3 分层约束
views.py仅做参数校验、鉴权、响应拼装- 业务规则(锁校验、命名约束、合并规则)全部下沉
services/ - 任何写操作必须记录审计日志(操作人、前后值、时间)
- 耗时 >500ms 的批量操作与重算流程必须异步化
四、API 设计原则
- 页面路由与数据 API 分离:
- 页面:
/complex/... - 数据:
/api/complex/...
- 页面:
- 列表筛选、Tab 切换、矩阵加载优先 HTMX 局刷。
- 楼盘名称/地址修改遵循数据治理规则:
name不允许普通编辑页直接改address走纠错流程
- 锁定状态前置校验:
lock_info/lock_building/lock_room/lock_standard_room。 - 统一错误协议:
- JSON:
{"error":"...","code":"..."} - HTMX: 片段 +
HX-Triggertoast
- JSON:
五、端点清单(核心)
5.1 页面路由(SSR + HTMX 容器)
| 路径 | 方法 | 鉴权 | 说明 |
|---|---|---|---|
/complex/list/ |
GET | 是 | 楼盘列表主页面(含完整度面板与筛选容器) |
/complex/create/ |
GET | 是 | 新增楼盘页面 |
/complex/{complex_id}/ |
GET | 是 | 楼盘详情主页面(多 Tab 容器) |
/complex/{complex_id}/edit/ |
GET | 是 | 编辑楼盘页面 |
/complex/region/ |
GET | 是 | 区域管理(城区/商圈)页面 |
5.2 HTMX 片段端点
| 路径 | 方法 | 用途 | 返回 |
|---|---|---|---|
/complex/fragments/list-table/ |
POST | 列表筛选/排序/分页局刷 | HTML |
/complex/fragments/completeness-panel/ |
GET | 顶部完整度指标面板局刷 | HTML |
/complex/{id}/fragments/tab/{tab}/ |
GET | 详情 Tab 懒加载 | HTML |
/complex/{id}/fragments/building-list/ |
POST | 楼栋管理列表局刷 | HTML |
/complex/{id}/fragments/structure-matrix/ |
POST | 结构矩阵局刷 | HTML |
/complex/region/fragments/district-table/ |
POST | 城区列表局刷 | HTML |
/complex/region/fragments/business-area-table/ |
POST | 商圈列表局刷 | HTML |
fragment 端点必须校验
HX-Request=true,否则返回 400。
5.3 JSON API(P0)
| 端点 | 方法 | 权限 code(建议) | 说明 |
|---|---|---|---|
/api/complex/ |
POST | complex.base.create.allow |
新增楼盘(US-001) |
/api/complex/list/query/ |
POST | complex.base.view.scope |
楼盘列表查询(US-002) |
/api/complex/{id}/detail/ |
GET | complex.base.view.scope |
楼盘详情聚合(US-002) |
/api/complex/{id}/base-info/ |
PATCH | complex.base.edit.allow |
编辑楼盘基础信息(US-001) |
/api/complex/{id}/lock/release/ |
POST | complex.lock.release.allow |
解锁楼盘(锁权限) |
/api/complex/{id}/buildings/query/ |
POST | complex.base.view.scope |
楼栋列表查询 |
/api/complex/{id}/buildings/ |
POST | complex.building.edit.allow |
新增楼栋 |
/api/complex/{id}/room-units/query/ |
POST | complex.base.view.scope |
结构矩阵查询 |
/api/complex/regions/districts/query/ |
POST | complex.region.manage.allow |
城区列表查询(US-003) |
/api/complex/regions/districts/ |
POST | complex.region.manage.allow |
新增城区(US-003) |
/api/complex/regions/districts/{id}/ |
PATCH | complex.region.manage.allow |
编辑城区 |
/api/complex/regions/business-areas/query/ |
POST | complex.region.manage.allow |
商圈列表查询(US-003) |
/api/complex/regions/business-areas/ |
POST | complex.region.manage.allow |
新增商圈(US-003) |
/api/complex/regions/business-areas/{id}/ |
PATCH | complex.region.manage.allow |
编辑商圈 |
/api/complex/regions/business-areas/merge/ |
POST | complex.region.manage.allow |
合并商圈 |
/api/complex/regions/districts/merge/ |
POST | complex.region.manage.allow |
合并城区 |
六、关键 API 规范(请求/响应)
6.1 新增楼盘
POST /api/complex/
{
"name": "万科城市花园",
"district_id": "uuid",
"address": "上海市闵行区XX路XX号",
"address_summary": "XX路XX弄",
"property_usage_types": ["residential"],
"building_structure": "unit_room",
"business_area_ids": ["uuid1", "uuid2"],
"school_ids": ["uuid3"]
}
成功 201:
{
"id": "uuid",
"message": "保存成功",
"redirect_url": "/complex/uuid/"
}
6.2 楼盘列表查询
POST /api/complex/list/query/
{
"keyword": "万科",
"filters": {
"district_ids": ["uuid"],
"usage_types": ["residential"],
"has_coordinate": true
},
"sort": {"field": "updated_at", "order": "desc"},
"pagination": {"mode": "keyset", "cursor": "opaque_cursor", "limit": 20}
}
6.3 编辑楼盘基础信息
PATCH /api/complex/{id}/base-info/
{
"address_summary": "海波路1000弄",
"built_years": [2005, 2008],
"ownership_category": ["commodity_residential"],
"remarks": "已校验最新物业信息"
}
规则:
- 若
lock_info=true且无解锁权限,返回 403 name字段不允许通过该接口修改,返回 400
6.4 新增商圈
POST /api/complex/regions/business-areas/
{
"district_id": "uuid",
"name": "江桥新城"
}
规则:
district_id + name唯一- 商圈必须归属城区
七、HTMX 交互约定
7.1 Header 约定
- 请求:
HX-Request: true - 成功:
HX-Trigger: {"toast":{"level":"success","message":"操作成功"}} - 失败:
HX-Trigger: {"toast":{"level":"error","message":"操作失败"}} - 跳转:
HX-Redirect: /complex/{id}/
7.2 模板分片命名
| 场景 | 模板 |
|---|---|
| 楼盘列表 | templates/complex/fragments/list_table.html |
| 完整度面板 | templates/complex/fragments/completeness_panel.html |
| 楼栋列表 | templates/complex/fragments/building_list.html |
| 结构矩阵 | templates/complex/fragments/structure_matrix.html |
| 城区列表 | templates/complex/fragments/district_table.html |
| 商圈列表 | templates/complex/fragments/business_area_table.html |
八、权限与数据范围
8.1 最小权限矩阵(P0 建议)
| 能力 | 权限 code |
|---|---|
| 查看楼盘列表/详情范围 | complex.base.view.scope |
| 新增/编辑楼盘基础信息 | complex.base.create.allow / complex.base.edit.allow |
| 解锁楼盘 | complex.lock.release.allow |
| 楼栋与结构维护 | complex.building.edit.allow |
| 区域管理(城区/商圈) | complex.region.manage.allow |
8.2 数据域规则
最终可见数据 = scope 过滤 ∩ 业务过滤(启用状态、软删过滤)
- 所有查询必须
deleted_at IS NULL - 区域管理默认只展示
is_active=true,可选查看停用项
九、异步任务与缓存策略
9.1 Celery 任务
| 任务 | 触发时机 | 说明 |
|---|---|---|
complex_completeness_recalc_task |
数据管理员点击“重新计算” | 重算完整度指标面板 |
complex_price_trend_refresh_task |
夜间定时 | 价格走势数据聚合(T+1) |
complex_merge_cleanup_task |
合并楼盘后 | 处理关联表与索引重建 |
任务参数必须包含
tenant_schema_name,任务开头显式切 schema。
9.2 Redis Key 规范
| Key | TTL | 说明 |
|---|---|---|
{schema}:complex:list:query:{hash} |
60s | 热门筛选缓存 |
{schema}:complex:detail:{id} |
120s | 详情聚合缓存 |
{schema}:complex:completeness:panel |
300s | 完整度指标缓存 |
{schema}:complex:region:districts |
300s | 城区字典缓存 |
{schema}:complex:region:business_areas:{district_id} |
300s | 商圈字典缓存 |
十、性能与可靠性约束
- 列表查询强制 Keyset 分页,禁止 OFFSET 大页深翻。
- 楼盘检索优先使用
search_vector+trgm索引。 - 详情页按 Tab 懒加载,避免一次拉全量聚合。
- 合并与批量改动使用事务;失败必须回滚。
- 区域与楼盘维护接口需限流,防止误操作风暴。
十一、安全与合规
- 楼盘锁定状态必须在服务层强校验,不允许绕过。
- 所有写操作记录审计:操作人、IP、前后值。
- 地图类外部 API 调用不得暴露密钥到前端。
- 删除有关联数据(楼盘、区域)必须返回阻断型错误提示。
十二、错误码建议
| code | HTTP | 场景 |
|---|---|---|
COMPLEX_NOT_FOUND |
404 | 楼盘不存在或无权限 |
COMPLEX_LOCKED_INFO |
403 | 楼盘信息锁定不可编辑 |
COMPLEX_NAME_EDIT_FORBIDDEN |
400 | 禁止直接修改楼盘名称 |
COMPLEX_REGION_REQUIRED |
400 | 商圈未归属城区 |
COMPLEX_REGION_DUPLICATED |
409 | 城区/商圈重名冲突 |
COMPLEX_PERMISSION_DENIED |
403 | 权限不足 |
十三、测试映射
13.1 P0 User Story 映射
| User Story | 最低覆盖 |
|---|---|
| US-COMPLEX-001 | 新增/编辑楼盘成功、必填校验、锁定校验 |
| US-COMPLEX-002 | 列表关键词筛选、分页、详情 Tab 懒加载 |
| US-COMPLEX-003 | 城区商圈新增编辑、归属约束、冲突校验 |
测试文件:tests/integration/complex/test_us_complex.py
13.2 强制测试约束
- 集成测试使用
TenantClient - HTMX 请求携带
HTTP_HX_REQUEST=true - 权限三态覆盖:200 / 403 / 302
- 外部服务(地图/R2/Redis)全部 mock
十四、落地顺序建议
- 先打通楼盘列表查询 + 详情聚合(US-COMPLEX-002)
- 再完成新增/编辑与锁校验(US-COMPLEX-001)
- 最后完成区域管理(US-COMPLEX-003)
- P1 再接照片、价格走势、学校管理
十五、文档同步规则
- 枚举变更:同步
DATA_MODEL/ENUMS.md - 权限 code 变更:同步
DATA_MODEL/DATA_MODEL_PERMISSION.md - 数据结构变更:同步
DATA_MODEL/DATA_MODEL_COMPLEX.md - API 变更:同步本文件与
PRD/TASK.md对应条目