11 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
关联 PRD: PRD/组织人事管理/组织人事管理模块PRD.md(v1.2)
关联数据模型: DATA_MODEL/DATA_MODEL_ORG.md(本方案不重复 DDL)
关联契约规范: TECH_STACK/API_CONTRACT.md(全局 API 契约权威)
关联枚举字典: DATA_MODEL/ENUMS.md
最后更新: 2026-04-27
变更历史
| 日期 | 变更人 | 变更内容 |
|---|---|---|
| 2026-04-30 | Atlas | 补充“变更历史”章节(文档治理) |
一、文档定位与边界
本文件只定义组织人事模块的:
- 服务边界与模块协作
- API 端点设计(重点)
- HTMX 局刷协议
- 权限接入、异动审计、缓存与性能约束
- 测试与验收映射
不在本文件展开:
org_units/staff/staff_transfer_logs/staff_reward_punish/staff_accounts结构细节。以DATA_MODEL_ORG.md为唯一权威。
二、范围定义(以 TASK.md 为准)
2.1 P0 必须覆盖
- US-ORG-001:管理员维护公司组织结构(部门/门店树)
- US-ORG-002:管理员查看与维护员工列表
- US-ORG-003:管理员办理员工入职并创建系统账号
2.2 P1/P2 预留
- US-ORG-010:员工离职与调动
- US-ORG-011:员工通讯录
- US-ORG-012:员工职务管理
- US-ORG-020:全局异动记录
- US-ORG-021:员工奖惩记录
- US-ORG-022:门店分布地图
三、模块架构边界
3.1 模块职责(apps/org)
- 管理组织树(公司→事业部→大区→区域→片区→门店→店组→职能)
- 管理员工主档(任职、联系方式、账号、状态)
- 管理入职与账号开通主流程
- 维护人事异动审计链路(入职/调动/离职/复职等)
3.2 外部依赖
| 依赖模块 | 依赖内容 | 依赖方式 |
|---|---|---|
apps/account |
新员工账号创建、初始密码策略、登录状态联动 | Service 调用 |
apps/permission |
组织/员工管理权限校验 | PermissionChecker |
apps/property |
员工离职/调动时业务归属迁移(预留) | 异步任务 |
apps/client |
客源归属迁移(预留) | 异步任务 |
core/encryption.py |
手机号/证件号加密存储与脱敏 | 统一工具 |
core/cache.py |
组织树缓存、员工选择器缓存 | Redis |
Celery |
批量导出、跨模块归属迁移、异动统计重算 | 异步任务 |
3.3 分层约束
views.py仅做参数校验、权限门禁、响应组装- 组织层级规则(店组必须挂门店、经纪人归属限制)必须在
services/强校验 - 员工状态变更必须联动写
staff_transfer_logs(不可删除) - 与账号相关操作通过
AccountService,禁止跨模块直写登录表
四、API 设计原则
- 页面路由与数据 API 分离:
- 页面:
/org/... - 数据:
/api/org/...
- 页面:
- 组织树、员工列表、异动记录采用 HTMX 局刷,减少全页刷新。
- 手机号/证件号默认脱敏展示,明文查看须权限与审计。
- 账号状态(启用/冻结)与员工状态变更必须一致性联动。
- 所有异动事件统一错误协议与日志结构,便于审计与报表。
五、端点清单(核心)
5.1 页面路由(SSR + HTMX 容器)
| 路径 | 方法 | 鉴权 | 说明 |
|---|---|---|---|
/org/structure/ |
GET | 是 | 组织结构主页面(组织树 + 员工列表) |
/org/departments/create/ |
GET | 是 | 新增部门页面 |
/org/departments/{org_id}/ |
GET | 是 | 部门详情 |
/org/departments/{org_id}/edit/ |
GET | 是 | 编辑部门 |
/org/staff/{staff_id}/ |
GET | 是 | 员工详情页(多 Tab) |
/org/transfer-logs/ |
GET | 是 | 全局异动记录页(预留) |
5.2 HTMX 片段端点
| 路径 | 方法 | 用途 | 返回 |
|---|---|---|---|
/org/fragments/org-tree/ |
GET | 左侧组织树局刷 | HTML |
/org/fragments/staff-table/ |
POST | 员工列表筛选/分页局刷 | HTML |
/org/staff/{id}/fragments/tab/{tab}/ |
GET | 员工详情 Tab 懒加载 | HTML |
/org/fragments/department-staff-selector/ |
GET | 选择器弹层局刷 | HTML |
fragment 端点必须校验
HX-Request=true,否则 400。
5.3 JSON API(P0)
| 端点 | 方法 | 权限 code(建议) | 说明 |
|---|---|---|---|
/api/org/departments/tree/ |
GET | hr.org.view.scope |
组织树加载(US-001) |
/api/org/departments/ |
POST | hr.org.edit.allow |
新增部门(US-001) |
/api/org/departments/{id}/ |
PATCH | hr.org.edit.allow |
编辑部门(US-001) |
/api/org/departments/{id}/close/ |
POST | hr.org.edit.allow |
关闭部门 |
/api/org/staff/query/ |
POST | hr.staff.view.scope |
员工列表查询(US-002) |
/api/org/staff/{id}/detail/ |
GET | hr.staff.view.scope |
员工详情(US-002) |
/api/org/staff/onboard/ |
POST | hr.staff.create.allow |
办理入职+建账号(US-003) |
/api/org/staff/{id}/base-info/ |
PATCH | hr.staff.edit.allow |
编辑员工基础信息(US-002) |
/api/org/staff/{id}/account/freeze/ |
POST | hr.staff.account.manage.allow |
冻结账号(预留) |
/api/org/staff/{id}/account/unfreeze/ |
POST | hr.staff.account.manage.allow |
解冻账号(预留) |
/api/org/staff/{id}/phone/view/ |
POST | hr.staff.phone.view.allow |
查看完整手机号(审计) |
六、关键 API 规范(请求/响应)
6.1 新增部门
POST /api/org/departments/
{
"name": "都市港湾店二组",
"parent_id": "uuid",
"type": "group",
"address_city": "上海",
"address_district": "闵行区",
"address_detail": "XX路XX号",
"manager_id": "uuid"
}
规则:
type=group时父节点必须为store- 违反层级约束返回 400
6.2 员工列表查询
POST /api/org/staff/query/
{
"keyword": "张三",
"filters": {
"org_unit_ids": ["uuid"],
"status": ["active", "probation"],
"job_category": ["置业顾问"]
},
"sort": {"field": "updated_at", "order": "desc"},
"pagination": {"mode": "keyset", "cursor": "opaque_cursor", "limit": 20}
}
6.3 办理入职并创建账号
POST /api/org/staff/onboard/
{
"name": "李雷",
"phone": "13800000000",
"org_unit_id": "uuid",
"job_title": "高级业务员",
"job_category": "置业顾问",
"role_codes": ["agent"],
"supervisor_id": "uuid"
}
成功 201:
{
"staff_id": "uuid",
"user_id": 12345,
"initial_password_sent": true,
"message": "入职办理成功"
}
联动要求:
- 创建
staff - 创建/绑定
auth_user - 写入一条
staff_transfer_logs(transfer_type='onboard')
6.4 查看员工手机号(审计)
POST /api/org/staff/{id}/phone/view/
{
"reason": "入职资料核对"
}
规则:
- 必须有
hr.staff.phone.view.allow - 返回明文仅本次有效
- 必须写入审计日志(操作者、时间、原因)
七、HTMX 交互约定
7.1 Header 约定
- 请求:
HX-Request: true - 成功:
HX-Trigger: {"toast":{"level":"success","message":"操作成功"}} - 失败:
HX-Trigger: {"toast":{"level":"error","message":"操作失败"}} - 跳转:
HX-Redirect: /org/staff/{id}/
7.2 模板分片命名
| 场景 | 模板 |
|---|---|
| 组织树 | templates/org/fragments/org_tree.html |
| 员工列表 | templates/org/fragments/staff_table.html |
| 员工详情-异动记录 | templates/org/fragments/staff_transfer_logs.html |
| 部门人员选择器 | templates/org/fragments/department_staff_selector.html |
八、权限与数据范围
8.1 最小权限矩阵(P0 建议)
| 能力 | 权限 code |
|---|---|
| 查看组织结构范围 | hr.org.view.scope |
| 编辑组织结构 | hr.org.edit.allow |
| 查看员工列表范围 | hr.staff.view.scope |
| 新建员工 | hr.staff.create.allow |
| 编辑员工 | hr.staff.edit.allow |
| 账号冻结/恢复 | hr.staff.account.manage.allow |
| 查看员工手机号 | hr.staff.phone.view.allow |
8.2 数据范围叠加
最终可见数据 = scope 过滤 ∩ 员工状态过滤 ∩ 组织层级过滤
- 系统管理员可走
is_system_admin短路 - 普通管理员按 scope 限制组织子树
九、异步任务与缓存策略
9.1 Celery 任务
| 任务 | 触发时机 | 说明 |
|---|---|---|
org_staff_export_task |
导出员工列表 | 异步导出 Excel |
org_transfer_affiliation_task |
离职/调动后(预留) | 迁移房源/客源归属 |
org_transfer_summary_task |
每日定时 | 异动统计重算 |
9.2 Redis Key 规范
| Key | TTL | 说明 |
|---|---|---|
{schema}:org:tree:{staff_id} |
300s | 组织树缓存 |
{schema}:org:staff:list:{hash} |
60s | 员工筛选缓存 |
{schema}:org:staff:detail:{staff_id} |
120s | 员工详情聚合缓存 |
{schema}:org:selector:staff:{org_unit_id} |
300s | 选择器缓存 |
写操作成功后必须主动失效相关 key。
十、性能与可靠性约束
- 组织树查询基于
path前缀与索引,避免递归 N+1。 - 员工列表采用 Keyset 分页,避免深分页性能退化。
- 员工详情按 Tab 懒加载,避免一次加载全量档案。
- 批量操作(导入/导出/调动)需限流与幂等控制。
十一、安全与合规
- 手机号与证件号全程加密存储,前端默认脱敏。
- 以下动作必须写
staff_transfer_logs:入职、调动、离职、复职、上级变更、冻结/解冻。 staff.status='resigned'或staff.status='frozen'时,auth_user.is_active=False。- 恢复在职后才可重新启用账号。
十二、错误码建议
| code | HTTP | 场景 |
|---|---|---|
ORG_UNIT_NOT_FOUND |
404 | 部门不存在或无权限 |
ORG_INVALID_HIERARCHY |
400 | 组织层级违反规则(如店组不挂门店) |
STAFF_NOT_FOUND |
404 | 员工不存在或无权限 |
STAFF_PHONE_DUPLICATED |
409 | 手机号冲突 |
STAFF_ACCOUNT_CREATE_FAILED |
500 | 账号创建失败 |
ORG_PERMISSION_DENIED |
403 | 权限不足 |
十三、测试映射
13.1 P0 User Story 映射
| User Story | 最低覆盖 |
|---|---|
| US-ORG-001 | 组织树查询、新增/编辑部门、层级约束校验 |
| US-ORG-002 | 员工列表筛选、详情加载、权限过滤 |
| US-ORG-003 | 入职建档+账号创建、必填校验、异动日志写入 |
测试文件:tests/integration/org/test_us_org.py
13.2 强制测试约束
- 集成测试使用
TenantClient - HTMX 请求携带
HTTP_HX_REQUEST=true - 权限三态:200 / 403 / 302
- 外部服务(短信/邮件/Redis/Celery)全部 mock
十四、落地顺序建议
- 先实现组织树与员工列表查询(US-ORG-001/002)
- 再实现入职流程与账号开通(US-ORG-003)
- 补齐审计与缓存失效机制
- 再推进离职/调动、通讯录、奖惩等 P1/P2 能力
十五、文档同步规则
- 枚举变更:同步
DATA_MODEL/ENUMS.md - 权限 code 变更:同步
DATA_MODEL/DATA_MODEL_PERMISSION.md - 数据结构变更:同步
DATA_MODEL/DATA_MODEL_ORG.md - API 变更:同步本文件与
PRD/TASK.md对应条目