文档更新
This commit is contained in:
@@ -1,420 +0,0 @@
|
||||
# PRD: 客户端发布管理模块
|
||||
**状态**: Draft
|
||||
**作者**: 产品经理
|
||||
**最后更新**: 2026-04-30(v1.2)
|
||||
**版本**: 1.2
|
||||
**所属系统**: Fonrey 房产经纪管理系统
|
||||
**关联模块**: 系统管理
|
||||
**干系人**: 工程负责人、运维负责人、Platform Admin(平台超级管理员)
|
||||
|
||||
## 变更历史
|
||||
|
||||
| 版本 | 日期 | 作者 | 变更说明 |
|
||||
|------|------|------|---------|
|
||||
| v1.0 | 2026-04-24 | 产品经理 | 初稿 |
|
||||
| v1.1 | 2026-04-30 | 产品经理 | Persona 与命名修正:① Story 4 / Story 5 责任角色由 Tenant Admin(租户管理员)修正为 Platform Admin(平台超级管理员),客户端版本上传与版本分布监控属于平台运营职责,跨租户统一管理;② §5.3 版本管理后台从"租户系统管理模块"迁移至"平台运营后台",明确 public schema 跨租户、Tenant Admin 与 Agent 无访问权限、不配置 RBAC permission_code;③ 全部 API 路径 `/api/client/updates/...` 重命名为 `/api/release/updates/...`,避免与客源管理模块(apps/client/)命名空间冲突,与 AGENTS.md §3 的 `apps/release/` 目录约定对齐;④ 头部"关联模块"由"系统管理、权限管理"修订为"系统管理"(不再涉及租户 RBAC);⑤ 干系人列表 Tenant Admin → Platform Admin。 |
|
||||
| v1.2 | 2026-04-30 | 产品经理 | Story 5 验收标准追加"按租户统计安装数"能力:① 新增验收项——可查看任意租户的"当前活跃安装数(最近 24h)"与"历史装机总数";② 新增验收项——全平台租户活跃榜视图,按 `tenant_code` + 租户名称 + 活跃安装数 + 历史装机数列表展示,按活跃安装数降序。底层数据由 `public.client_heartbeats` 表的 `tenant_id` 维度聚合提供(详见 DATA_MODEL_PUBLIC v1.5 §5.1 租户维度安装/活跃统计查询专区)。 |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 1. 问题陈述
|
||||
|
||||
### 背景
|
||||
|
||||
Fonrey 房产经纪管理系统当前为纯 Web 应用,依赖用户自行通过浏览器访问。然而在实际部署场景中,经纪公司的终端设备环境高度复杂:
|
||||
|
||||
- **浏览器版本参差不齐**:经纪人使用的 Windows 设备可能运行 IE11、旧版 Edge、或未更新的 Chrome,导致 HTMX + Alpine.js 等现代前端技术出现兼容性问题,系统体验碎片化
|
||||
- **交付和部署门槛高**:IT 能力薄弱的经纪公司无法独立配置浏览器访问方式,URL 记忆成本高,容易访问错误版本
|
||||
- **版本管理缺失**:后端服务升级后,用户仍可能使用旧版缓存页面操作,导致接口不兼容和功能异常
|
||||
- **无官方入口**:用户通过私发链接访问系统,存在钓鱼仿冒风险,且无法统一品牌形象
|
||||
|
||||
### 目标用户
|
||||
|
||||
| 角色 | 使用场景 | 使用频率 |
|
||||
|------|---------|----------|
|
||||
| Agent(经纪人) | 下载安装客户端、日常登录使用系统、接受自动更新 | 每日 |
|
||||
| 店长/经理 | 同上 | 每日 |
|
||||
| Platform Admin(平台超级管理员) | 发布新版本、管理安装包下载地址、监控客户端版本分布 | 按需 |
|
||||
| IT 运维人员 | 维护更新服务器、签名证书、构建发布流水线 | 按发布周期 |
|
||||
|
||||
### 核心痛点
|
||||
|
||||
1. **无法控制用户使用的浏览器环境**,兼容性问题无法从根源解决
|
||||
2. **升级依赖用户主动刷新浏览器**,后端 API 变更时旧客户端可能造成数据错误
|
||||
3. **缺乏官方分发渠道**,无法向终端用户传递信任感和版本一致性保障
|
||||
4. **SaaS 多租户管理系统需要统一、可控的客户端入口**,避免因客户端环境差异导致的支持成本上升
|
||||
|
||||
---
|
||||
|
||||
## 2. 目标与成功指标
|
||||
|
||||
| 目标 | 指标 | 当前基准 | 目标值 | 衡量周期 |
|
||||
|------|------|---------|--------|---------|
|
||||
| 消除浏览器兼容性问题 | 因浏览器兼容产生的支持工单数 | 待统计 | 降低 ≥ 90% | 上线后 60 天 |
|
||||
| 提升版本一致性 | 在线用户中使用最新版本客户端的比例 | 0%(无客户端) | ≥ 95% | 版本发布后 7 天 |
|
||||
| 降低部署门槛 | 新客户从获取安装包到完成首次登录的时间 | 无基准 | ≤ 10 分钟 | 上线后首批客户反馈 |
|
||||
| 自动更新成功率 | 客户端自动更新完成率(收到更新通知 → 升级完成) | 无基准 | ≥ 98% | 每次版本发布后 48 小时 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 非目标(本期不做)
|
||||
|
||||
- **不支持 macOS / Linux 客户端**:目标用户群体 99% 使用 Windows,macOS 版本为后续规划
|
||||
- **不支持移动端 App(iOS / Android)**:移动端为 v2 规划,本期不涉及
|
||||
- **不开发私有化部署的离线安装方案**:本期聚焦 SaaS 在线版,私有化部署另行规划
|
||||
- **不包含客户端内置的离线模式**:系统需联网使用,客户端不缓存业务数据供离线访问
|
||||
- **不包含客户端层面的安全加固(如代码混淆、反逆向)**:本期以功能交付为优先,安全加固列入后续迭代
|
||||
|
||||
---
|
||||
|
||||
## 4. 用户故事与验收标准
|
||||
|
||||
---
|
||||
|
||||
### Story 1:经纪人下载并安装客户端
|
||||
|
||||
**As** Agent(经纪人),**I want** 通过公司提供的网址下载一个安装程序并完成安装,**So that** 我可以立即打开登录界面使用 Fonrey 系统,无需手动配置浏览器。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 官方下载页面可通过指定 URL 访问,页面展示最新版本号、发布日期及下载按钮
|
||||
- [ ] 下载产物为单一 `.exe` 安装包(或免安装便携版 `.zip`),文件大小控制在合理范围内
|
||||
- [ ] 双击安装包后,安装向导步骤不超过 3 步(下一步 → 选择安装路径 → 安装),无需勾选额外组件
|
||||
- [ ] 安装完成后,桌面自动生成快捷方式(图标为 Fonrey 品牌 Logo)
|
||||
- [ ] 首次启动后直接显示登录界面,无需用户手动输入任何 URL
|
||||
- [ ] 安装包经过代码签名,Windows SmartScreen 不弹出"无法识别的应用"警告
|
||||
- [ ] 安装过程无需管理员权限(支持用户级安装到 `%APPDATA%` 目录),降低企业 IT 审批障碍
|
||||
|
||||
---
|
||||
|
||||
### Story 2:经纪人使用客户端正常登录并使用系统
|
||||
|
||||
**As** Agent(经纪人),**I want** 打开客户端后直接访问 Fonrey 系统的完整功能,**So that** 我的日常使用体验与使用 Chrome 浏览器无差异,且不受本机安装的浏览器版本影响。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 客户端内嵌现代 Chromium 内核(如基于 Electron 或 WebView2),版本不低于 Chromium 100,支持现代 Web 标准(ES2020、CSS Grid、Fetch API 等)
|
||||
- [ ] HTMX 局部刷新、Alpine.js 状态交互、Tailwind CSS 样式在客户端中渲染效果与 Chrome 最新版一致
|
||||
- [ ] 支持 Cookie / Session 存储,登录状态在客户端关闭后保留(复用 Django Session 机制)
|
||||
- [ ] 文件上传(图片、附件)、文件下载(Excel 导出)在客户端中正常工作
|
||||
- [ ] 客户端窗口支持最大化、最小化、拖拽调整大小,支持多显示器
|
||||
- [ ] 客户端标题栏显示应用名称和当前版本号(如:`Fonrey 房睿 v1.2.3`)
|
||||
- [ ] 客户端不显示浏览器默认的地址栏、书签栏、扩展工具栏,保持沉浸式应用体验
|
||||
|
||||
---
|
||||
|
||||
### Story 3:客户端感知新版本并自动升级
|
||||
|
||||
**As** Agent(经纪人),**I want** 客户端在有新版本时自动提示并完成升级,**So that** 我无需手动下载安装,始终使用最新版本,不会因版本落后导致功能异常。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 客户端启动时及运行期间(每隔 4 小时)自动向更新服务器检查最新版本
|
||||
- [ ] 有新版本时,客户端右下角弹出非阻断式通知:"发现新版本 vX.X.X,点击立即更新",用户可选择"立即更新"或"稍后提醒"
|
||||
- [ ] 点击"立即更新"后,客户端在后台静默下载更新包,进度条显示下载进度
|
||||
- [ ] 下载完成后提示用户"更新已就绪,重启客户端完成安装",用户选择"立即重启"或"下次启动时安装"
|
||||
- [ ] 重启后,新版本生效,标题栏版本号更新,历史会话自动恢复(用户无需重新登录)
|
||||
- [ ] 支持强制更新模式:服务端可标记某版本为"强制升级",客户端不展示"稍后提醒"选项,必须升级后方可继续使用(用于重大 API 兼容性变更场景)
|
||||
- [ ] 更新失败时(网络中断、磁盘空间不足等),客户端显示错误提示并保持当前版本正常运行,不影响用户当前操作
|
||||
|
||||
---
|
||||
|
||||
### Story 4:Platform Admin(平台超级管理员)发布新版本
|
||||
|
||||
**As** Platform Admin(平台超级管理员),**I want** 通过平台运营后台上传新版客户端安装包并配置版本信息,**So that** 全平台所有租户的客户端能感知到更新并引导用户升级。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 平台运营后台提供"客户端版本管理"页面(位于平台运营后台下,不在租户系统管理模块)
|
||||
- [ ] 支持上传 `.exe` 安装包,并填写版本号(遵循 SemVer:`X.Y.Z`)、版本说明(更新日志,支持 Markdown)、发布日期
|
||||
- [ ] 支持设置版本类型:普通更新 / 强制更新
|
||||
- [ ] 支持设置版本状态:草稿(不对外生效)/ 已发布 / 已下线
|
||||
- [ ] 发布后,更新服务器 API 即时返回最新版本信息,客户端下次检测时可感知
|
||||
- [ ] 支持版本回滚:将指定历史版本重新设为"已发布",自动将当前版本标记为已下线
|
||||
- [ ] 支持查看各版本的下载量和活跃客户端版本分布统计
|
||||
|
||||
---
|
||||
|
||||
### Story 5:Platform Admin(平台超级管理员)监控客户端版本分布
|
||||
|
||||
**As** Platform Admin(平台超级管理员),**I want** 跨租户查看当前所有在线客户端的版本分布情况,**So that** 了解全平台升级覆盖率,对仍在使用旧版本的客户端发出提醒或强制升级。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 客户端版本管理页面展示版本分布统计:各版本在线客户端数量及占比(饼图或条形图)
|
||||
- [ ] 支持按租户维度查看版本分布(区分不同经纪公司的版本使用情况,便于平台超管识别落后租户)
|
||||
- [ ] 支持**按租户统计安装数**:可查看任意租户的"当前活跃安装数(最近 24h)"与"历史装机总数(不论是否活跃)",用于评估各租户的客户端覆盖率与渗透率
|
||||
- [ ] 支持全平台租户活跃榜视图:以列表形式展示各 active 状态租户的 `tenant_code`、租户名称、活跃安装数、历史装机总数,按活跃安装数降序排列
|
||||
- [ ] 支持对指定版本范围的用户推送"强制更新"通知(如:将所有低于 v1.5.0 的客户端标记为强制更新)
|
||||
|
||||
---
|
||||
|
||||
## 5. 功能详细说明
|
||||
|
||||
### 5.1 技术架构选型
|
||||
|
||||
#### 5.1.1 客户端技术方案
|
||||
|
||||
基于 Fonrey 现有技术栈(Django + HTMX + Alpine.js + Tailwind CSS,后端已采用 Docker Compose 部署),客户端本质是一个**内嵌现代 Chromium 内核的原生 Windows 应用外壳(Shell)**,其核心职责是:
|
||||
|
||||
1. 提供操作系统级原生窗口(标题栏、任务栏图标、托盘)
|
||||
2. 内嵌高版本 Chromium 内核加载 Fonrey Web 应用 URL
|
||||
3. 实现版本检测与自动更新逻辑
|
||||
4. 处理文件下载、本地存储等 OS 级能力
|
||||
|
||||
**推荐方案:Electron(主选)**
|
||||
|
||||
| 维度 | Electron | Tauri | WebView2 封装 |
|
||||
|------|---------|-------|--------------|
|
||||
| 内核控制 | ✅ 捆绑 Chromium,100% 可控 | ❌ 依赖系统 WebView,版本不可控 | ⚠️ 依赖 Windows 内置 WebView2 Runtime |
|
||||
| 包体大小 | ~150MB(可接受) | ~5MB | ~5MB |
|
||||
| 生态成熟度 | ✅ 最成熟,社区最大 | ✅ 较新但活跃 | ⚠️ 微软官方但文档偏少 |
|
||||
| 自动更新支持 | ✅ `electron-updater` 成熟方案 | ✅ 内置更新器 | ⚠️ 需自行实现 |
|
||||
| 跨平台 | ✅ Win/Mac/Linux | ✅ | ❌ 仅 Windows |
|
||||
| 团队技术匹配 | ✅ 主进程用 Node.js,渲染层纯 Web | ⚠️ 主进程需 Rust | ✅ 主进程用 C# |
|
||||
| **推荐度** | **✅ 主选** | 次选 | 备选 |
|
||||
|
||||
**选型决策**:采用 **Electron + electron-updater**。理由:
|
||||
|
||||
- 内嵌 Chromium 内核是本需求的核心约束,Electron 是唯一能 100% 保证内核版本可控的主流方案
|
||||
- `electron-updater` 配合 GitHub Releases 或自建 S3/R2 存储可实现完整的版本管理与自动更新流程,开发成本最低
|
||||
- 渲染层完全复用 Fonrey 现有 Web 技术栈,无需新增前端框架学习成本
|
||||
- 团队具备 JavaScript/Node.js 能力,主进程开发门槛可控
|
||||
|
||||
**技术决策**:客户端不内置任何业务逻辑,所有业务功能由服务端 Fonrey Web 应用提供。客户端仅负责加载 Web 应用、更新管理和 OS 级能力(窗口、托盘、文件下载路径)。
|
||||
|
||||
---
|
||||
|
||||
#### 5.1.2 更新服务架构
|
||||
|
||||
更新机制采用**差量检测 + 全量包下载**模式:
|
||||
|
||||
```
|
||||
客户端启动 / 定时检测(每4小时)
|
||||
│
|
||||
▼
|
||||
GET /api/release/updates/latest?platform=win32&arch=x64¤t_version=1.2.0
|
||||
│
|
||||
▼
|
||||
更新服务器(Fonrey 后端 Django API)
|
||||
返回:{ latest_version, download_url, release_notes, force_update, checksum }
|
||||
│
|
||||
├── 无更新 → 继续正常运行
|
||||
│
|
||||
└── 有更新 → 弹出通知
|
||||
│
|
||||
├── 用户点击"立即更新" → 后台下载 .exe / NSIS 更新包
|
||||
│ │
|
||||
│ └── 下载完成 → 校验 SHA256 → 提示重启安装
|
||||
│
|
||||
└── 用户选择"稍后" → 下次启动再提示
|
||||
```
|
||||
|
||||
**更新包存储**:上传至 Cloudflare R2(与现有对象存储一致),通过 Cloudflare CDN 加速下载,全国用户均可获得稳定下载速度。
|
||||
|
||||
**版本 API 端点**(新增至 Django 后端):
|
||||
|
||||
| 端点 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/api/release/updates/latest/` | GET | 客户端查询最新版本,返回版本信息和下载 URL |
|
||||
| `/api/release/updates/` | GET | 管理端查询版本列表(需认证) |
|
||||
| `/api/release/updates/` | POST | 管理端发布新版本(需管理员权限) |
|
||||
| `/api/release/updates/<id>/` | PATCH | 管理端修改版本状态(发布/下线/强制) |
|
||||
|
||||
---
|
||||
|
||||
#### 5.1.3 安装包签名与分发
|
||||
|
||||
**代码签名**:
|
||||
- 使用 EV 代码签名证书(推荐购买 DigiCert 或 Sectigo EV 证书)
|
||||
- 通过 `electron-builder` 在 CI/CD 构建时自动签名
|
||||
- 签名后安装包经 Windows SmartScreen 审核,用户安装时不触发安全警告
|
||||
|
||||
**安装包分发**:
|
||||
- 官方下载页:独立 HTML 页面托管于 Cloudflare Pages 或 Nginx 静态站
|
||||
- 页面展示:最新版本号 + 发布日期 + 更新日志 + 下载按钮
|
||||
- 下载 URL 格式:`https://download.fonrey.com/releases/v1.2.3/fonrey-setup-1.2.3-win.exe`
|
||||
- 同时提供便携版(Portable):`fonrey-portable-1.2.3-win.zip`,供无安装权限的企业环境使用
|
||||
|
||||
---
|
||||
|
||||
### 5.2 客户端功能规格
|
||||
|
||||
#### 5.2.1 主窗口
|
||||
|
||||
| 属性 | 规格 |
|
||||
|------|------|
|
||||
| 默认窗口尺寸 | 1280 × 800(最小:1024 × 600) |
|
||||
| 标题栏 | 显示 `Fonrey 房睿 v{version}`,含原生最小化/最大化/关闭按钮 |
|
||||
| 内嵌 URL | 启动时加载 `https://{tenant}.fonrey.com`(或私有化部署地址,可配置) |
|
||||
| 地址栏 | 不显示(沉浸式应用模式) |
|
||||
| 右键菜单 | 仅保留"复制"/"粘贴"/"检查元素(仅开发模式)",移除"查看源代码"等浏览器默认项 |
|
||||
| 外部链接 | 点击 `target="_blank"` 链接时,在系统默认浏览器中打开,不在客户端内新窗口打开 |
|
||||
|
||||
#### 5.2.2 系统托盘
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| 托盘图标 | Fonrey Logo,鼠标悬停显示 `Fonrey 房睿 - 已连接` / `- 离线` |
|
||||
| 右键菜单 | 打开主窗口 / 检查更新 / 关于 / 退出 |
|
||||
| 最小化行为 | 点击关闭按钮时最小化至托盘(不退出程序),用户通过托盘图标恢复窗口 |
|
||||
|
||||
#### 5.2.3 网络状态感知
|
||||
|
||||
| 状态 | 客户端行为 |
|
||||
|------|-----------|
|
||||
| 正常联网 | 加载 Fonrey Web 应用,状态栏显示"已连接" |
|
||||
| 网络断开 | 显示全屏提示页:"网络连接已断开,请检查您的网络后重试",提供"重新连接"按钮 |
|
||||
| 服务器维护 | 服务器返回 503 时,展示维护提示页(内容由服务端控制) |
|
||||
|
||||
#### 5.2.4 文件下载处理
|
||||
|
||||
- Excel 导出等文件下载触发时,客户端调用系统原生"另存为"对话框,用户选择保存路径
|
||||
- 下载完成后,状态栏显示"下载完成,点击打开"提示,点击可直接打开文件
|
||||
|
||||
---
|
||||
|
||||
### 5.3 版本管理后台(平台运营后台新增页面)
|
||||
|
||||
**页面路径**:平台运营后台 → 客户端发布管理
|
||||
|
||||
> **归属说明**:本页面归属 Platform Admin(平台超级管理员),位于平台运营后台(public schema 跨租户),不在租户的"系统管理"模块下。Tenant Admin 与 Agent 均无访问权限。
|
||||
|
||||
#### 5.3.1 版本列表
|
||||
|
||||
| 列 | 说明 |
|
||||
|----|------|
|
||||
| 版本号 | SemVer 格式,如 `v1.2.3` |
|
||||
| 版本类型 | 普通更新 / 强制更新(红色标签) |
|
||||
| 状态 | 草稿 / 已发布(绿色)/ 已下线(灰色) |
|
||||
| 发布时间 | 版本设为已发布的时间 |
|
||||
| 下载量 | 该版本安装包被下载次数 |
|
||||
| 操作 | 发布 / 下线 / 编辑 / 复制下载链接 |
|
||||
|
||||
#### 5.3.2 新增/编辑版本表单
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 版本号 | 文本输入 | 是 | 格式:`X.Y.Z`,自动校验 SemVer 格式 |
|
||||
| 版本类型 | 单选 | 是 | 普通更新 / 强制更新 |
|
||||
| 最低兼容版本 | 文本输入 | 否 | 低于该版本的客户端将被强制更新(如填写 `1.0.0`,则低于此版本的客户端强制升级) |
|
||||
| 安装包(EXE) | 文件上传 | 是 | 上传至 Cloudflare R2,最大 500MB |
|
||||
| 便携版(ZIP) | 文件上传 | 否 | 同上 |
|
||||
| SHA256 校验值 | 文本输入(自动填充) | 是 | 上传后系统自动计算并填充,用于客户端下载完成后校验完整性 |
|
||||
| 更新日志 | Markdown 文本区域 | 是 | 展示给用户看的版本说明,最多 2000 字 |
|
||||
| 发布说明(内部) | 文本区域 | 否 | 仅内部查看的技术说明,不对外展示 |
|
||||
| 状态 | 单选 | 是 | 草稿 / 立即发布 |
|
||||
|
||||
#### 5.3.3 版本分布统计
|
||||
|
||||
| 图表 | 说明 |
|
||||
|------|------|
|
||||
| 版本分布饼图 | 按客户端版本号统计当前活跃用户数量及占比 |
|
||||
| 升级进度趋势图 | 新版本发布后,各天累计升级完成的用户比例(折线图) |
|
||||
| 租户版本明细 | 按租户(经纪公司)展示其员工的客户端版本分布 |
|
||||
|
||||
---
|
||||
|
||||
### 5.4 更新 API 规格
|
||||
|
||||
#### GET `/api/release/updates/latest/`
|
||||
|
||||
**请求参数(Query String)**:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `platform` | string | 是 | 平台标识,如 `win32` |
|
||||
| `arch` | string | 是 | CPU 架构,如 `x64` / `arm64` |
|
||||
| `current_version` | string | 是 | 客户端当前版本号,如 `1.2.0` |
|
||||
|
||||
**响应示例(有新版本)**:
|
||||
|
||||
```json
|
||||
{
|
||||
"has_update": true,
|
||||
"latest_version": "1.3.0",
|
||||
"force_update": false,
|
||||
"download_url": "https://download.fonrey.com/releases/v1.3.0/fonrey-setup-1.3.0-win.exe",
|
||||
"portable_url": "https://download.fonrey.com/releases/v1.3.0/fonrey-portable-1.3.0-win.zip",
|
||||
"checksum_sha256": "a1b2c3d4...",
|
||||
"release_notes": "## v1.3.0 更新内容\n- 新增客源智能配房功能\n- 修复房源列表筛选条件保存异常",
|
||||
"release_date": "2026-05-01"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例(已是最新)**:
|
||||
|
||||
```json
|
||||
{
|
||||
"has_update": false,
|
||||
"latest_version": "1.3.0"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 技术实现注意事项
|
||||
|
||||
### 6.1 依赖关系
|
||||
|
||||
| 依赖项 | 说明 | 负责方 | 风险等级 |
|
||||
|--------|------|--------|---------|
|
||||
| Electron 框架 | 客户端技术基础,需评估 License(MIT,商业可用) | 前端/客户端工程师 | 低 |
|
||||
| EV 代码签名证书 | 需提前申请,EV 证书审核周期 1-2 周 | IT/运维 | 中(需提前排期) |
|
||||
| Cloudflare R2 存储桶 | 存放安装包,利用现有账号新增 bucket | 运维 | 低 |
|
||||
| `electron-updater` | 自动更新库,需配合更新 API 端点实现 | 客户端工程师 | 低 |
|
||||
| Django 更新 API | 新增 `/api/release/updates/` 相关接口 | 后端工程师 | 低 |
|
||||
| CI/CD 构建流水线 | 自动构建、签名、上传安装包 | 运维/DevOps | 中 |
|
||||
|
||||
### 6.2 已知风险
|
||||
|
||||
| 风险 | 可能性 | 影响 | 缓解措施 |
|
||||
|------|--------|------|---------|
|
||||
| EV 证书申请延迟 | 中 | 高(无签名包无法正常分发) | MVP 阶段可使用普通 OV 证书临时过渡,但需向用户说明安全警告原因 |
|
||||
| Electron 包体过大导致下载放弃 | 低 | 中 | 使用 `electron-builder` 的 `asar` 压缩 + 分片下载;首包控制在 150MB 以内 |
|
||||
| 企业网络拦截 CDN 下载 | 中 | 中 | 提供备用下载 URL(直连服务器),支持客户手动下载后本地安装 |
|
||||
| 自动更新期间用户强制关闭 | 低 | 低 | 更新包下载完成后才替换原文件,下载中断不影响现有版本正常运行 |
|
||||
| 多租户场景下 URL 配置问题 | 低 | 高 | 客户端启动时加载的 URL 通过配置文件指定,支持定制化部署;SaaS 版统一指向主域名 |
|
||||
|
||||
### 6.3 开放问题(开发启动前必须解决)
|
||||
|
||||
- [ ] **租户 URL 如何分发到客户端?** 选项 A:客户端硬编码主域名,由服务端重定向到租户子域(`fonrey.com` → `{tenant}.fonrey.com`);选项 B:安装包内置配置文件,由销售/运维在分发给客户前填写租户子域。——**Owner**: 产品 + 工程 **Deadline**: 开发启动前
|
||||
- [ ] **代码签名证书采购主体和预算是否确认?** — **Owner**: IT 负责人 **Deadline**: 立项后 1 周
|
||||
- [ ] **CI/CD 平台选型是否确定?**(GitHub Actions / Jenkins / 其他)— **Owner**: 运维负责人 **Deadline**: 开发启动前
|
||||
- [ ] **便携版(Portable ZIP)是否纳入 v1 范围?** 便携版可解决企业无安装权限场景,但增加测试成本。— **Owner**: PM **Deadline**: 立项后 1 周
|
||||
|
||||
---
|
||||
|
||||
## 7. 发布计划
|
||||
|
||||
| 阶段 | 时间 | 受众 | 成功门槛 |
|
||||
|------|------|------|---------|
|
||||
| 内部 Alpha | 开发完成后 1 周 | 内部团队 + 1 家种子客户 | 核心流程无 P0 Bug,自动更新机制验证通过 |
|
||||
| 封闭 Beta | Alpha + 2 周 | 3-5 家头部客户 | 安装成功率 ≥ 95%,自动更新成功率 ≥ 95%,无 P0/P1 Bug |
|
||||
| 正式发布(GA) | Beta + 1 周 | 全部客户 | Beta 阶段目标达成 |
|
||||
|
||||
**回滚标准**:若正式发布后 24 小时内出现以下情况,立即下线该版本并恢复上一稳定版本为"已发布":
|
||||
- 自动更新失败率 > 5%
|
||||
- 客户端白屏/崩溃率 > 2%
|
||||
- 收到 P0 级安全漏洞报告
|
||||
|
||||
---
|
||||
|
||||
## 8. 附录
|
||||
|
||||
### 8.1 竞品参考
|
||||
|
||||
| 产品 | 客户端方案 | 更新机制 |
|
||||
|------|-----------|---------|
|
||||
| 企业微信 | Electron + 自研内核 | 强制更新,启动时自动下载 |
|
||||
| 飞书 | Electron | 后台静默更新,重启生效 |
|
||||
| 钉钉 | Electron | 同上 |
|
||||
|
||||
> 房产经纪行业的竞品(如房客多、云客优)均采用 Electron 方案,验证了技术路线的合理性。
|
||||
|
||||
### 8.2 术语表
|
||||
|
||||
| 术语 | 定义 |
|
||||
|------|------|
|
||||
| SemVer | 语义化版本控制(Semantic Versioning):`主版本号.次版本号.补丁号`,如 `1.2.3` |
|
||||
| Electron | 由 GitHub 开发的开源框架,允许使用 Web 技术(HTML/CSS/JS)构建跨平台桌面应用,内嵌 Chromium 和 Node.js |
|
||||
| electron-updater | Electron 生态中成熟的自动更新库,支持增量更新和全量更新 |
|
||||
| EV 证书 | Extended Validation 代码签名证书,由 CA 机构颁发,可消除 Windows SmartScreen 安全警告 |
|
||||
| SHA256 | 安全散列算法,用于验证下载文件的完整性,防止篡改或下载损坏 |
|
||||
| Portable | 便携版,无需安装,解压即用,适合无管理员权限的企业环境 |
|
||||
835
Project/fonrey/PRD/平台管理后台/平台管理后台PRD.md
Normal file
835
Project/fonrey/PRD/平台管理后台/平台管理后台PRD.md
Normal file
@@ -0,0 +1,835 @@
|
||||
# PRD:平台管理后台(Platform Admin Console)
|
||||
|
||||
**状态**:Draft
|
||||
**作者**:产品经理
|
||||
**最后更新**:2026-05-02
|
||||
**版本**:v1.0
|
||||
**所属系统**:Fonrey 房产经纪管理系统
|
||||
**关联模块**:权限管理(仅平台侧管理员账号体系)、登录管理(管理员登录与 MFA)、所有租户业务模块(间接,仅作运营/监控对象)
|
||||
**利益相关方**:工程负责人、运营团队、安全合规、客户成功团队、IT 运维
|
||||
|
||||
---
|
||||
|
||||
## 变更历史
|
||||
|
||||
| 版本 | 日期 | 作者 | 变更说明 |
|
||||
|------|------|------|---------|
|
||||
| v1.0 | 2026-05-02 | 产品经理 | 由 `PRD/系统管理/系统管理模块PRD.md` (v1.3) 与 `PRD/发布管理/客户端发布管理模块PRD.md` (v1.2) 合并而来;统一面向平台管理员视角,统一规划页面路由与业务 API 操作清单。原两份 PRD 文件同步删除,参见 `ADR-20260502-001`。 |
|
||||
|
||||
> **本 PRD 取代以下两份历史文档**:
|
||||
> - `PRD/系统管理/系统管理模块PRD.md`(v1.3,已删除,被本 PRD 替代)
|
||||
> - `PRD/发布管理/客户端发布管理模块PRD.md`(v1.2,已删除,被本 PRD 替代)
|
||||
>
|
||||
> 决策依据:`ADR-20260502-001`(REQ)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 问题陈述
|
||||
|
||||
### 1.1 背景
|
||||
|
||||
Fonrey(房睿)是面向房产经纪公司的 B2B SaaS 平台,采用 `django-tenants` 实现 PostgreSQL Schema 级别多租户隔离,同时通过 Electron 桌面客户端为终端经纪人提供统一入口。随着平台商业化推进,**平台运营团队**需要一套独立、跨租户的「平台管理后台」(Platform Admin Console)来统一承担:
|
||||
|
||||
1. 租户全生命周期管理(开通、挂起、注销、License 续期)
|
||||
2. 平台版本治理(基础数据版本、租户数据版本、灰度升级、回滚)
|
||||
3. 数据备份与恢复(灾难场景应对)
|
||||
4. 客户端发布治理(桌面客户端版本上线、强制升级、版本分布监控)
|
||||
5. 操作审计与合规
|
||||
6. 平台管理员账号与安全(MFA、IP 白名单、强制登出)
|
||||
|
||||
平台管理后台部署于平台公共域名(与租户应用域名隔离),数据落在 `public` schema,跨租户。Tenant Admin 与 Agent 一律无访问权限。
|
||||
|
||||
### 1.2 核心痛点
|
||||
|
||||
| 痛点 | 影响方 | 当前代价 |
|
||||
|------|--------|---------|
|
||||
| 无统一租户管理界面,开通 / 挂起 / 注销依赖人工脚本 | 运营团队 | 高错误风险,操作耗时 |
|
||||
| 平台版本升级需停机,影响所有租户 | 全量用户 | SLA 违约风险 |
|
||||
| 数据备份无策略,灾难恢复依赖人工 | 平台稳定性 | 数据丢失风险 |
|
||||
| 高危操作无审计轨迹 | 管理层 / 合规 | 法律与客户信任风险 |
|
||||
| 客户端浏览器版本碎片化,兼容性问题层出 | Agent / 客户成功 | 支持成本飙升 |
|
||||
| 客户端无统一发布渠道,旧版本与新后端 API 不兼容 | 全量用户 | 数据错误风险 |
|
||||
| 无法跨租户掌握客户端版本分布与覆盖率 | Platform Admin | 无法定向催更 |
|
||||
|
||||
### 1.3 目标用户
|
||||
|
||||
| 角色 | 使用场景 | 频率 |
|
||||
|------|---------|------|
|
||||
| Platform Admin(平台超级管理员) | 全局配置、高危操作、版本上线、强制升级 | 低频(每周) |
|
||||
| 运营人员(Ops Operator) | 日常租户管理、监控巡检、客户咨询响应 | 高频(每日) |
|
||||
| 只读审计员(Read-only Auditor) | 日志查询、合规报告导出 | 中频(每周) |
|
||||
|
||||
> 本 PRD **不涉及**租户内部的 Tenant Admin、Agent 角色——他们对本后台无访问权限。
|
||||
|
||||
---
|
||||
|
||||
## 2. 目标与成功指标
|
||||
|
||||
| 目标 | 指标 | 当前基线 | 目标值 | 测量窗口 |
|
||||
|------|------|---------|--------|---------|
|
||||
| 租户开通效率 | 新租户开通耗时 | 人工脚本 ~30 分钟 | < 5 分钟(含自动初始化) | 上线后 30 天 |
|
||||
| 平台升级零停机 | 升级期间受影响租户数 | 全量中断 | 灰度阶段 ≤ 5% 租户 | 每次升级 |
|
||||
| 数据恢复能力 | RTO(单租户恢复时间) | 无标准流程 | < 2 小时 | v1 上线即达标 |
|
||||
| 操作合规覆盖 | 高危操作审计日志覆盖率 | 0% | 100% | 上线后 30 天 |
|
||||
| 管理员安全 | 平台管理员 MFA 启用率 | 0% | 100%(强制) | 上线即达标 |
|
||||
| 客户端兼容性问题消除 | 因浏览器兼容产生的支持工单数 | 待统计 | 降低 ≥ 90% | 客户端上线后 60 天 |
|
||||
| 客户端版本一致性 | 在线用户使用最新客户端比例 | 0%(无客户端) | ≥ 95% | 版本发布后 7 天 |
|
||||
| 客户端自动更新成功率 | 收到通知 → 升级完成的成功率 | 无基准 | ≥ 98% | 每次发布后 48 小时 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 非目标(Non-Goals)
|
||||
|
||||
**不在 v1 实现**:
|
||||
- 自动化账单计费、多币种支持、Webhook 自定义集成市场
|
||||
- 租户端自助迁移工具
|
||||
- 客户响应数据导出请求(Story「响应客户数据导出请求」暂缓,列入后续迭代)
|
||||
|
||||
**不属于本后台**:
|
||||
- 租户内业务权限的细粒度配置(见权限管理模块 PRD)
|
||||
- 客服工单系统、SLA 自动赔付
|
||||
- macOS / Linux 桌面客户端、移动端 App
|
||||
- 客户端离线模式、私有化离线安装方案
|
||||
- 客户端代码混淆 / 反逆向加固
|
||||
|
||||
**不支持**:
|
||||
- 移动端浏览器访问平台管理后台(运营场景明确为 PC 桌面)
|
||||
- 多语言界面(运营团队为内部人员,中文已满足)
|
||||
|
||||
---
|
||||
|
||||
## 4. 用户角色与核心故事
|
||||
|
||||
### Persona A — 运营人员 Lily(日常租户管理)
|
||||
|
||||
> 负责 Fonrey 的日常运营,每天处理新客户开通、异常租户处理、客户咨询。使用 PC 浏览器登录平台管理后台。
|
||||
|
||||
#### Story A1:新租户开通
|
||||
|
||||
> 作为运营人员,我希望通过填写表单快速完成租户开通,并由系统自动完成数据库初始化与欢迎通知,无需手动执行脚本。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 表单提交后,系统在后台自动创建 PostgreSQL Schema 并注入默认配置(见 §5.1.2「默认配置内容」),完成耗时 < 60 秒
|
||||
- [ ] 默认配置注入包含两部分:
|
||||
- **权限定义(PermissionDef)**:注入平台所有权限码定义(`permission_code`、描述、模块归属),作为该租户 RBAC 体系基础
|
||||
- **系统默认角色与权限绑定**:按「角色权限矩阵.md」注入 7 个系统内置业务角色(置业顾问、店管、区管、区总、副总、总经、其他职能),并完成角色—权限绑定
|
||||
- [ ] 初始 Tenant Admin(以联系人手机号创建)**不通过业务角色赋权**,由系统在租户创建时直接写入「租户管理员」专属权限集合;该集合独立于 7 个业务角色之外,不在租户角色管理界面显示,不可由 Tenant Admin 自行修改或分配。新增/变更租户管理员须由平台运营方在本后台操作
|
||||
- [ ] 新租户创建后:平台运营管理员收到站内消息;租户联系人收到欢迎邮件(见下方「欢迎邮件规范」)
|
||||
- [ ] 联系人无邮箱时,运营人员可在租户详情页下载「入驻信息 PDF 文档」,通过微信等渠道转发
|
||||
- [ ] 租户访问地址采用统一域名 + Tenant Code 参数形式(`https://app.fonrey.com/?tenant={Tenant Code}`),无需子域名;详情页展示该链接,可一键复制
|
||||
- [ ] 创建失败时回滚所有已创建资源,并显示明确错误原因
|
||||
|
||||
**欢迎邮件规范**(联系人有邮箱时自动发送):
|
||||
|
||||
| 字段 | 内容 |
|
||||
|------|------|
|
||||
| 主题 | 【房睿平台】您的账号已开通,欢迎登录 |
|
||||
| 收件人 | 租户联系人邮箱 |
|
||||
| 正文 | 公司名称、**Tenant Code**、登录地址、Tenant Admin 手机号(脱敏后三位)、**系统初始密码**(明文,首次登录后强制修改)、客服联系方式 |
|
||||
| 备注 | 初始密码由系统随机生成(12 位,含大小写字母+数字),发送后立即标记为「首次登录强制修改」 |
|
||||
|
||||
**入驻信息 PDF**(无邮箱客户的备选方案):
|
||||
- 包含与欢迎邮件相同的关键信息
|
||||
- 入口:租户详情 → 基本信息 Tab → 「下载入驻信息」按钮
|
||||
- 文件名:`{公司名称}_入驻信息_{日期}.pdf`
|
||||
|
||||
#### Story A2:挂起问题租户
|
||||
|
||||
> 作为运营人员,我希望快速冻结欠费租户的访问,同时保证数据不丢失,并在欠费解决后一键恢复。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 挂起后,该租户所有用户登录跳转至「账号已暂停」提示页;平台后台对该租户数据访问不受影响
|
||||
- [ ] 支持设置到期时间,到期后系统自动恢复租户状态,并发送通知邮件
|
||||
- [ ] 所有挂起 / 恢复操作记录于审计日志,包含操作人、时间、原因
|
||||
|
||||
#### Story A3:License 时效管理与到期自动挂起
|
||||
|
||||
> 作为运营人员(或 Platform Admin),我希望每个租户能设置 License 有效期,到期后系统自动挂起租户,并在到期前提前预警。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 每个租户「基本信息」中包含 **License 到期日期**字段,由 Platform Admin 在创建或续费时设定
|
||||
- [ ] 系统每日自动检查 License 到期,到期后自动挂起,挂起原因标注为「License 到期」
|
||||
- [ ] 自动挂起后,租户联系人收到通知邮件;Platform Admin 续费后可手动解除挂起
|
||||
- [ ] **提前 15 天预警**:租户内 Tenant Admin 登录后管理界面顶部出现倒计时横幅:「您的 License 将于 X 天后到期({到期日期}),请联系平台续费」
|
||||
- [ ] 倒计时横幅仅对 Tenant Admin 可见,不影响普通 Agent
|
||||
- [ ] License 到期日期在租户列表与详情页均可见,支持「即将到期(15 天内)」筛选
|
||||
|
||||
#### Story A4:查看与控制租户用户数(License 计费维度)
|
||||
|
||||
> 作为运营人员(或 Platform Admin),我希望看到每个租户的当前用户数,并能设置用户数上限,以便根据 License 授权进行管控。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 租户列表新增「当前用户数」列,显示该租户当前有效用户总数(含 Tenant Admin + 全部 Agent,不含已删除/离职)
|
||||
- [ ] 租户详情页「基本信息」Tab 显示:当前用户数 / License 授权用户数上限(如:12 / 50)
|
||||
- [ ] Platform Admin 可设置「License 授权用户数上限」字段;达到上限时,Tenant Admin 在该租户内无法继续创建新用户,并收到提示:「当前用户数已达 License 上限,请联系平台扩容」
|
||||
- [ ] Platform Admin 可随时调整用户数上限(扩容 / 缩容),变更写入审计日志
|
||||
- [ ] 租户列表支持按「用户数已满(≥ 上限)」筛选,便于平台运营主动识别需续费的租户
|
||||
|
||||
> **Story A5:响应客户数据导出请求** — **状态**:暂缓(v1 不实现,列入后续迭代)。
|
||||
|
||||
---
|
||||
|
||||
### Persona B — Platform Admin David(系统升级、回滚与版本治理)
|
||||
|
||||
> 负责平台技术运维,周期性执行版本升级,关注升级稳定性与租户影响面。拥有所有高危操作权限。
|
||||
|
||||
#### Story B1:灰度系统升级
|
||||
|
||||
> 作为 Platform Admin,我希望先对内测租户升级新版本,验证稳定后再全量推送,避免一次性影响所有客户。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 升级前自动执行健康检查,存在异常服务时阻断升级并提示
|
||||
- [ ] 支持指定目标租户进行灰度升级,灰度租户名单可编辑
|
||||
- [ ] 升级过程实时展示进度(每个租户的升级状态),支持查看升级日志
|
||||
- [ ] 升级失败时系统自动告警,并提供一键回滚入口
|
||||
|
||||
#### Story B2:升级失败回滚
|
||||
|
||||
> 作为 Platform Admin,我希望在升级出现问题时立即回滚至上一稳定版本,并生成事件报告。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 回滚操作触发前自动保存当前状态快照
|
||||
- [ ] 支持全量回滚或单租户回滚
|
||||
- [ ] 回滚完成后生成事件报告:失败原因、回滚耗时、影响范围
|
||||
- [ ] 回滚操作需二次身份验证确认(MFA)
|
||||
|
||||
#### Story B3:查看平台与租户版本总览
|
||||
|
||||
> 作为 Platform Admin,我希望在管理界面一眼看到整个平台的版本情况,包括基础数据版本和每个租户各自的数据升级版本。
|
||||
|
||||
**验收标准**:
|
||||
|
||||
「版本总览」页面分两部分:
|
||||
|
||||
- **Part 1:平台基础数据版本**
|
||||
- [ ] 展示当前平台基础数据(公共 Schema 中的 PermissionDef、系统配置等 seed 数据)的版本号
|
||||
- [ ] 该版本对所有租户一致,每次平台升级为一次性全量升级
|
||||
- [ ] 字段:版本号、最后升级时间、升级描述、升级执行人
|
||||
|
||||
- **Part 2:租户数据升级版本**
|
||||
- [ ] 列表展示每个租户当前数据版本号(即该租户 Schema 已完成的 migration 版本)
|
||||
- [ ] 灰度升级下各租户版本可能不一致
|
||||
- [ ] 字段:租户名称、当前数据版本、上次升级时间、升级状态(最新 / 待升级 / 升级中 / 升级失败)
|
||||
- [ ] 支持按「待升级」「升级失败」筛选,快速定位异常租户
|
||||
- [ ] 点击租户行可跳转至该租户详情的「备份记录」Tab
|
||||
|
||||
- [ ] 页面支持手动刷新;版本数据允许最多 5 分钟缓存延迟
|
||||
|
||||
---
|
||||
|
||||
### Persona C — Platform Admin David(客户端发布治理)
|
||||
|
||||
> 同 Persona B,但聚焦桌面客户端版本上线、强制升级与跨租户版本分布。
|
||||
|
||||
#### Story C1:发布新版本客户端
|
||||
|
||||
> 作为 Platform Admin,我希望通过本后台上传新版客户端安装包并配置版本信息,使全平台所有租户的客户端能感知到更新并引导升级。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 平台管理后台提供「客户端版本管理」页面(位于本后台一级菜单,与租户系统管理隔离)
|
||||
- [ ] 支持上传 `.exe` 安装包,并填写:
|
||||
- 版本号(SemVer:`X.Y.Z`,自动校验格式)
|
||||
- 版本类型(普通更新 / 强制更新)
|
||||
- 最低兼容版本(低于此版本的客户端将被强制升级)
|
||||
- 更新日志(Markdown,最多 2000 字,对外展示)
|
||||
- 内部发布说明(不对外)
|
||||
- [ ] 支持版本状态:草稿(不对外生效)/ 已发布 / 已下线
|
||||
- [ ] 上传成功后,系统自动计算 SHA256 校验值并填充到该版本元数据,作为客户端下载完成后的完整性校验依据
|
||||
- [ ] 发布后,客户端下次检测时即可感知(无需等待)
|
||||
- [ ] 支持版本回滚:将指定历史版本重新置为「已发布」,自动将当前版本标记为「已下线」
|
||||
- [ ] 支持便携版(Portable ZIP)作为可选上传项
|
||||
|
||||
#### Story C2:跨租户监控客户端版本分布
|
||||
|
||||
> 作为 Platform Admin,我希望跨租户查看当前所有在线客户端的版本分布,以了解全平台升级覆盖率,对仍使用旧版本的客户端发出提醒或强制升级。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 「客户端版本管理」页展示版本分布统计:各版本在线客户端数量及占比(饼图或条形图)
|
||||
- [ ] 支持按租户维度查看版本分布(区分不同经纪公司,便于识别落后租户)
|
||||
- [ ] 支持按租户统计安装数:可查看任一租户的「当前活跃安装数(最近 24h)」与「历史装机总数(不论是否活跃)」
|
||||
- [ ] 支持「全平台租户活跃榜」视图:以列表形式展示各 active 状态租户的 `tenant_code`、租户名称、活跃安装数、历史装机总数,按活跃安装数降序排列
|
||||
- [ ] 支持对指定版本范围的客户端推送「强制更新」标记(如:将所有低于 v1.5.0 的客户端标记为强制更新)
|
||||
- [ ] 支持升级进度趋势图:新版本发布后各天累计升级完成的用户比例
|
||||
|
||||
> **客户端侧用户故事不在本 PRD 范围**(如「Agent 下载安装客户端」「Agent 自动升级」)。这些故事面向终端用户使用的桌面 App,不属于平台管理后台职责。但本 PRD 通过 Story C1/C2 为客户端侧故事提供版本数据源与控制能力。
|
||||
|
||||
---
|
||||
|
||||
### Persona D — 只读审计员 Carol(合规审计)
|
||||
|
||||
> 负责平台合规审查,定期导出操作日志供法务或客户审查。无任何写权限。
|
||||
|
||||
#### Story D1:审计日志查询与导出
|
||||
|
||||
> 作为审计员,我希望按操作人、时间范围、操作类型筛选操作日志,并导出为报告。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 日志列表支持多维度筛选:操作人、时间范围、操作对象、操作类型(创建 / 修改 / 删除 / 高危)
|
||||
- [ ] 每条日志包含:操作人、操作时间、操作对象(租户/用户ID)、内容摘要、结果(成功/失败)、来源 IP
|
||||
- [ ] 支持导出筛选结果为 CSV
|
||||
|
||||
---
|
||||
|
||||
## 5. 功能详细说明
|
||||
|
||||
### 5.1 租户与 License 管理
|
||||
|
||||
#### 5.1.1 租户生命周期
|
||||
|
||||
**新建租户表单字段**:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 公司名称 | Text | ✅ | 最大 100 字符 |
|
||||
| 联系人 | Text | ✅ | 主联系人姓名 |
|
||||
| 联系人手机号 | Text | ✅ | 用于创建初始 Tenant Admin |
|
||||
| 联系邮箱 | Email | ❌(可选) | 发送欢迎邮件;无邮箱改用 PDF 下载 |
|
||||
| 所在地区 | Select | ✅ | 省市两级 |
|
||||
| 订阅套餐 | Select | ✅ | Basic / Professional / Enterprise |
|
||||
| License 到期日期 | Date | ✅ | 到期后自动挂起 |
|
||||
| License 授权用户数上限 | Number | ✅ | 用户数计费维度 |
|
||||
|
||||
**创建流程**:
|
||||
1. 表单校验通过后,后台异步任务执行:
|
||||
- 创建 PostgreSQL Schema(`tenant_{id}`)
|
||||
- 执行 Migrate 初始化表结构
|
||||
- 注入默认配置(见下方「默认配置内容」)
|
||||
- 生成初始密码(12 位随机),标记为「首次登录强制修改」
|
||||
- 联系邮箱已填写时:发送欢迎邮件(含 Tenant Code、初始密码、平台访问链接)
|
||||
2. 任务完成后更新租户状态为 `active`;失败则全量回滚并标记为 `failed`
|
||||
3. 生成唯一 Tenant ID(UUID)及 Tenant Code(12位纯数字,如 `202605023765`)
|
||||
|
||||
#### 5.1.2 默认配置内容(Schema 初始化时注入)
|
||||
|
||||
| 配置类型 | 内容 | 说明 |
|
||||
|---------|------|------|
|
||||
| 权限定义(PermissionDef) | 平台全量权限码 | 从 public schema 同步至租户 schema |
|
||||
| 系统默认业务角色 | 7 个内置角色(置业顾问/店管/区管/区总/副总/总经/其他职能)+ 角色—权限绑定 | 按「角色权限矩阵.md」 |
|
||||
| 初始 Tenant Admin 用户 | 以联系人手机号创建 | 写入「租户管理员」专属权限集合,独立于 7 个业务角色 |
|
||||
|
||||
#### 5.1.3 挂起(Suspend)
|
||||
|
||||
- **触发方式**:
|
||||
- 手动:运营人员选择挂起原因(欠费 / 违规 / 主动申请 / 其他)
|
||||
- 自动:系统每日检查 License 到期日期,到期自动挂起(原因「License 到期」)
|
||||
- 可设置挂起到期时间(留空表示永久挂起直至手动恢复)
|
||||
- 挂起效果:租户用户访问被拒,重定向至暂停提示页;平台管理后台对该租户数据访问不受影响
|
||||
- 自动恢复:手动设置了到期时间的挂起会到期自动恢复;License 到期挂起须 Platform Admin 手动恢复
|
||||
- 通知:挂起 / 恢复均向租户联系邮箱发送通知(无邮箱跳过)
|
||||
- License 到期前 15 天起,租户端 Tenant Admin 看到倒计时横幅
|
||||
|
||||
#### 5.1.4 删除(Delete)
|
||||
|
||||
| 模式 | 说明 |
|
||||
|------|------|
|
||||
| 软删除 | 标记删除状态,数据保留 30 天(默认,可配置)后自动清除 |
|
||||
| 硬删除 | 立即清除所有数据、Schema、存储资源;仅 Platform Admin 可操作 |
|
||||
|
||||
**删除前置条件**:
|
||||
1. 操作人必须确认数据导出已完成(勾选确认框)
|
||||
2. 硬删除需 MFA 二次验证
|
||||
3. 软删除冷静期内可在租户列表中执行「撤销删除」
|
||||
|
||||
删除完成后释放:访问域名 / Tenant Code、Cloudflare R2 存储桶、License 席位
|
||||
|
||||
#### 5.1.5 数据导出(Export)
|
||||
|
||||
> Story A5(响应客户数据导出请求)暂缓;本节描述能力为运营内部数据核查使用。
|
||||
|
||||
- 触发:管理员手动,选择目标租户 + 模块 + 格式
|
||||
- 异步执行,状态实时刷新(Pending → In Progress → Done / Failed)
|
||||
- 内容:结构化数据(CSV / JSON / SQL Dump)+ 文件资产 URL 清单(**不打包文件实体**)
|
||||
- 模块选项:客户数据 / 房源数据 / 交易记录 / 系统配置 / 全量
|
||||
- 存储:压缩后存于 Cloudflare R2 临时目录,签名下载链接 24 小时有效
|
||||
|
||||
**文件资产导出处理规则**(v1 决策):
|
||||
- R2 Bucket 配置为 public read,文件通过 CDN 持久 URL 形式内嵌于导出数据
|
||||
- 账号未硬删除前,CDN URL 持续有效
|
||||
- 迁移类需求(需要文件实体)走「完整备份」流程,不走「数据导出」
|
||||
|
||||
| 导出格式 | 图片字段示例 | 附件字段示例 |
|
||||
|---------|------------|------------|
|
||||
| CSV | `photos` 列:多个 CDN URL 以英文分号分隔 | `attachments` 列:`文件名\|CDN URL` 以分号分隔 |
|
||||
| JSON | `"photos": [{"url": "...", "filename": "...", "created_at": "..."}]` | `"attachments": [{"url": "...", "filename": "..."}]` |
|
||||
| SQL Dump | 文件元数据表原样导出,`file_url` 字段为 CDN URL | 同左 |
|
||||
|
||||
导出包附 `README.txt` 说明文件资产链接策略。
|
||||
|
||||
**数据导出 vs 完整备份**:
|
||||
|
||||
| 维度 | 数据导出(Export) | 完整备份(Backup) |
|
||||
|------|------------------|-----------------|
|
||||
| 用途 | 合规审计、数据核查、业务分析 | 灾难恢复、租户迁移 |
|
||||
| 文件资产 | CDN URL 清单 | 含 R2 文件实体 |
|
||||
| 完成时间 | 分钟级 | 小时级 |
|
||||
| 触发方式 | 运营人员手动 | 手动 / 系统自动(升级前) |
|
||||
| 存储成本 | 极低 | 较高 |
|
||||
|
||||
#### 5.1.6 数据备份(Snapshot)
|
||||
|
||||
- 自动触发:升级前系统对参与租户全量备份
|
||||
- 手动触发:管理员可在租户详情页发起
|
||||
- 内容:数据库 Schema(pg_dump)+ R2 文件存储(附件、图片)
|
||||
- 字段:备份时间、触发方式、备份大小、状态
|
||||
- 保留策略:默认最近 10 个版本,可在全局配置中调整
|
||||
- 存储:加密;目标可选(本地 / S3 / R2 / GCS)
|
||||
|
||||
#### 5.1.7 数据恢复(Restore)
|
||||
|
||||
恢复流程:
|
||||
```
|
||||
选择目标备份版本
|
||||
→ 二次确认(显示当前数据版本将被覆盖)
|
||||
→ 自动对当前数据生成临时快照
|
||||
→ 租户切换为维护模式
|
||||
→ 执行恢复
|
||||
→ 自动恢复服务 → 生成恢复报告
|
||||
```
|
||||
|
||||
报告字段:操作人、操作时间、恢复前/后版本、耗时、结果。
|
||||
|
||||
#### 5.1.8 套餐升级
|
||||
|
||||
- 升级路径:Basic → Professional → Enterprise
|
||||
- 升级前展示差异对比表(功能项、用户数上限、存储空间、API 额度)
|
||||
- 生效模式:立即 / 下一账期
|
||||
- 升级前自动备份;升级失败可一键回滚
|
||||
- 升级历史:时间、操作人、升级前后套餐
|
||||
|
||||
#### 5.1.9 租户用户与权限管理
|
||||
|
||||
**Tenant Admin 管理**:
|
||||
- 每个租户可设置 1 至多名 Tenant Admin
|
||||
- Platform Admin 可直接创建新用户并赋予 Tenant Admin,或从租户现有用户中指定
|
||||
- 支持新增 / 替换 / 撤销
|
||||
|
||||
**密码重置**(针对租户内任意用户):
|
||||
- 方式一:发送重置链接至注册邮箱(用户自助)
|
||||
- 方式二:管理员直接设置临时密码(首次登录强制修改)
|
||||
- 所有操作进审计日志
|
||||
|
||||
#### 5.1.10 租户监控与统计
|
||||
|
||||
**资源监控指标**:
|
||||
|
||||
| 指标 | 展示维度 |
|
||||
|------|---------|
|
||||
| CPU / 内存占用 | 实时折线图 |
|
||||
| 存储用量 | 当前值 vs 套餐上限 |
|
||||
| API 调用次数 | 当日 / 本月累计 |
|
||||
| 活跃用户数 | 当日活跃 |
|
||||
| 当日登录次数 | 累计折线图 |
|
||||
| 异常请求数 | 4xx / 5xx 分类 |
|
||||
| 慢查询数量 | > 500ms |
|
||||
|
||||
支持为每个指标配置阈值告警(邮件 / Webhook)。
|
||||
|
||||
**可用性 / SLA**:
|
||||
- 服务可用率统计:日 / 周 / 月
|
||||
- 故障事件记录:开始 / 恢复时间、持续时长、影响描述
|
||||
- SLA 达标率报告,可导出
|
||||
|
||||
---
|
||||
|
||||
### 5.2 平台版本治理
|
||||
|
||||
#### 5.2.1 系统升级流程
|
||||
|
||||
```
|
||||
上传/拉取升级包
|
||||
→ 自动健康检查(所有服务正常才允许)
|
||||
→ 配置升级策略:全量 / 灰度(指定内测租户)
|
||||
→ 升级前自动备份(参与本次升级的租户)
|
||||
→ 执行升级
|
||||
→ 实时展示升级进度(租户维度状态列表)
|
||||
→ 完成通知(成功/失败详情)
|
||||
```
|
||||
|
||||
**灰度升级策略**:
|
||||
- 维护「内测租户组」列表,由 Platform Admin 配置
|
||||
- 灰度阶段仅对内测租户升级,其余租户保持原版本
|
||||
- 内测验证通过(手动确认)后,触发全量升级
|
||||
|
||||
#### 5.2.2 升级回滚
|
||||
|
||||
- 触发:手动 / 自动(监控检测到错误率超阈值)
|
||||
- 范围:全量回滚 / 单租户回滚
|
||||
- 前置:自动保存当前状态快照
|
||||
- 后续:生成事件报告(失败原因、回滚耗时、受影响租户列表)
|
||||
- 必需:MFA 二次验证
|
||||
|
||||
#### 5.2.3 定时备份策略
|
||||
|
||||
| 配置项 | 选项 |
|
||||
|--------|------|
|
||||
| 备份频率 | 每小时 / 每日 / 每周 |
|
||||
| 执行时间窗口 | 默认每日 02:00 |
|
||||
| 保留数量 | 最近 N 个版本(默认 10) |
|
||||
| 存储目标 | 本地 / AWS S3 / Cloudflare R2 / GCS |
|
||||
|
||||
支持为单租户配置独立备份计划,覆盖全局策略。备份失败自动告警,支持手动重试。
|
||||
|
||||
#### 5.2.4 版本总览
|
||||
|
||||
见 Story B3 验收标准。该视图为运营提供「平台基础数据版本 + 各租户数据版本」双维度可见性,是灰度升级时代的版本治理核心入口。
|
||||
|
||||
---
|
||||
|
||||
### 5.3 客户端发布治理
|
||||
|
||||
> 本节面向 Persona C 的 Story C1 / C2。客户端本身的技术形态、自动更新机制、签名分发等实现细节属于技术方案范畴,请参见 `TECH_STACK/平台管理后台技术方案.md`。本 PRD 仅描述产品视角的业务能力。
|
||||
|
||||
#### 5.3.1 版本管理
|
||||
|
||||
平台管理后台提供独立的「客户端版本管理」一级页面,承担:
|
||||
|
||||
**版本列表展示字段**:
|
||||
|
||||
| 列 | 说明 |
|
||||
|----|------|
|
||||
| 版本号 | SemVer 格式,如 `v1.2.3` |
|
||||
| 版本类型 | 普通更新 / 强制更新(后者标红) |
|
||||
| 状态 | 草稿 / 已发布(绿)/ 已下线(灰) |
|
||||
| 发布时间 | 设为已发布的时间 |
|
||||
| 下载量 | 该版本安装包被下载次数 |
|
||||
| 操作 | 发布 / 下线 / 编辑 / 复制下载链接 |
|
||||
|
||||
**新增/编辑版本表单字段**:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 版本号 | Text | ✅ | SemVer,自动校验 |
|
||||
| 版本类型 | 单选 | ✅ | 普通更新 / 强制更新 |
|
||||
| 最低兼容版本 | Text | ❌ | 低于该版本的客户端被强制升级 |
|
||||
| 安装包(EXE) | File | ✅ | 上传至 R2,最大 500MB |
|
||||
| 便携版(ZIP) | File | ❌ | 同上 |
|
||||
| SHA256 校验值 | Text(自动) | ✅ | 上传后系统计算并填充 |
|
||||
| 更新日志 | Markdown | ✅ | 对外展示,最多 2000 字 |
|
||||
| 发布说明(内部) | Text | ❌ | 仅内部查看 |
|
||||
| 状态 | 单选 | ✅ | 草稿 / 立即发布 |
|
||||
|
||||
#### 5.3.2 版本分布统计
|
||||
|
||||
| 图表 | 说明 |
|
||||
|------|------|
|
||||
| 版本分布饼图 | 按客户端版本号统计当前活跃用户数量及占比 |
|
||||
| 升级进度趋势图 | 新版本发布后各天累计升级完成的用户比例 |
|
||||
| 租户版本明细 | 按租户展示其员工的客户端版本分布 |
|
||||
| 全平台租户活跃榜 | `tenant_code` + 租户名称 + 活跃安装数(最近 24h) + 历史装机总数,按活跃安装数降序 |
|
||||
|
||||
底层数据由 `public.client_heartbeats` 表的 `tenant_id` 维度聚合提供。
|
||||
|
||||
#### 5.3.3 强制更新推送
|
||||
|
||||
- Platform Admin 可对指定版本范围的客户端打上「强制更新」标记(如所有低于 v1.5.0 的客户端强制升级)
|
||||
- 客户端侧的强制更新行为(不展示「稍后提醒」、必须升级后方可继续使用)由客户端实现保障
|
||||
|
||||
---
|
||||
|
||||
### 5.4 平台管理后台总体规划
|
||||
|
||||
#### 5.4.1 页面清单与访问权限
|
||||
|
||||
> 以下为产品视角的页面清单。「页面路径」以业务可读形式表达,不约束技术实现(具体 URL 由技术方案决定)。所有页面均位于平台管理后台域,无访问权限的角色(Tenant Admin、Agent 及未登录用户)一律重定向到登录页或 403。
|
||||
|
||||
| # | 页面 | 路径(业务可读) | 访问权限 | 说明 |
|
||||
| --- | ----------- | -------------------------------- | --------------------------------------- | --------------------------------- |
|
||||
| 1 | 登录页 | `/admin/login` | 公开(仅平台管理员账号可登录) | 强制 MFA 配置 |
|
||||
| 2 | 仪表盘 | `/admin` | 全部三类管理员 | 平台总览、健康度、近期告警、最近高危操作 |
|
||||
| 3 | 租户列表 | `/admin/tenants` | Platform Admin / 运营人员(写)/ 审计员(只读) | 检索、筛选、快捷操作 |
|
||||
| 4 | 新建租户 | `/admin/tenants/new` | Platform Admin / 运营人员 | — |
|
||||
| 5 | 租户详情:基本信息 | `/admin/tenants/{id}` | 同租户列表 | 含 License、用户数、状态等编辑入口 |
|
||||
| 6 | 租户详情:用户管理 | `/admin/tenants/{id}/users` | 同上 | Tenant Admin 列表、用户列表、密码重置 |
|
||||
| 7 | 租户详情:套餐信息 | `/admin/tenants/{id}/plan` | 同上 | 套餐详情、用量、升级入口 |
|
||||
| 8 | 租户详情:监控 | `/admin/tenants/{id}/monitoring` | 同上 | 资源使用、SLA |
|
||||
| 9 | 租户详情:备份记录 | `/admin/tenants/{id}/backups` | Platform Admin(写)/ 运营人员(仅触发备份)/ 审计员(只读) | 备份列表、触发备份、恢复入口(仅 Platform Admin) |
|
||||
| 10 | 租户详情:操作历史 | `/admin/tenants/{id}/history` | 全部三类 | 该租户相关所有管理员操作日志 |
|
||||
| 11 | 系统版本管理 | `/admin/system/versions` | Platform Admin(写)/ 运营人员(只读)/ 审计员(只读) | 含「版本总览」(平台基础数据版本 + 各租户数据版本)、升级、回滚 |
|
||||
| 12 | 备份管理 | `/admin/system/backups` | Platform Admin(写)/ 运营人员(触发)/ 审计员(只读) | 全局备份计划、备份任务列表、恢复入口 |
|
||||
| 13 | 监控与告警 | `/admin/monitoring` | Platform Admin / 运营人员(写)/ 审计员(只读) | 全局监控图表、告警规则、告警历史 |
|
||||
| 14 | **客户端版本管理** | `/admin/client-releases` | Platform Admin(写)/ 运营人员(只读)/ 审计员(只读) | 版本列表、发布、下线、回滚、版本分布、租户活跃榜 |
|
||||
| 15 | 审计日志 | `/admin/audit-logs` | 全部三类(含审计员) | 多维度筛选、导出 CSV |
|
||||
| 16 | 管理员设置 | `/admin/settings/admins` | 仅 Platform Admin | 管理员账号、角色、MFA、IP 白名单、登录会话 |
|
||||
|
||||
#### 5.4.2 页面间导航逻辑(用户故事视角)
|
||||
|
||||
- 用户访问任一受保护页面但未登录 → 跳转 `/admin/login`
|
||||
- 登录成功且未配置 MFA → 强制跳转 MFA 配置向导后再进入仪表盘
|
||||
- 仪表盘的「最近高危操作」区域,每条记录可点击跳转到「审计日志」并自动以该记录为筛选条件
|
||||
- 仪表盘的「系统健康」区域,点击异常服务可跳转「监控与告警」对应租户/服务视图
|
||||
- 租户列表点击「公司名称」→ 进入「租户详情:基本信息」(默认 Tab)
|
||||
- 租户详情各 Tab 之间通过页内 Tab 切换,URL 同步变化(页面 5–10)
|
||||
- 租户详情「备份记录」中点击「恢复」→ 出现二次确认弹窗 + MFA 验证(仅 Platform Admin 可见)
|
||||
- 「系统版本管理」中点击某租户行 → 跳转到该租户的「备份记录」Tab
|
||||
- 「客户端版本管理」中点击「全平台租户活跃榜」中的租户名称 → 跳转到该租户「基本信息」Tab
|
||||
- 客户端版本「发布 / 下线 / 强制更新推送」操作 → 二次确认;强制更新推送额外要求 MFA
|
||||
- 任何高危操作(删除租户、数据恢复、系统回滚、客户端版本下线、强制更新推送)触发 MFA 二次确认弹窗
|
||||
- 用户超过 30 分钟无操作 → 自动登出,下次操作跳转登录页
|
||||
- 「管理员设置」中 Platform Admin 强制登出某管理员 → 该管理员的所有会话立即失效,下次请求跳转登录页
|
||||
|
||||
#### 5.4.3 仪表盘内容
|
||||
|
||||
| 模块 | 展示内容 |
|
||||
|------|---------|
|
||||
| 全局概览 | 总租户数、活跃租户数、本月新增 |
|
||||
| 系统健康 | 各核心服务状态(Django / PostgreSQL / Redis / Celery / R2) |
|
||||
| 近期告警 | 最近 24 小时告警,按严重程度分类 |
|
||||
| 资源概览 | 平台整体存储用量、API 调用量趋势 |
|
||||
| 客户端覆盖 | 当前活跃客户端总数、最新版本占比 |
|
||||
| 最近操作 | 最近 10 条高危操作审计记录 |
|
||||
|
||||
#### 5.4.4 租户列表
|
||||
|
||||
- 分页(默认 20 条/页)
|
||||
- 搜索:公司名称、Tenant Code、联系邮箱关键词
|
||||
- 筛选:状态(Active / Suspended / Deleted)、套餐、注册时间、**即将到期(15 天内)**、**用户数已满**
|
||||
- 列:公司名称、Tenant Code、套餐、状态、注册时间、活跃用户数 / License 上限、客户端最新版本占比
|
||||
- 快捷操作:查看详情、挂起、发起备份、数据导出
|
||||
|
||||
---
|
||||
|
||||
### 5.5 业务 API 操作清单(产品视角)
|
||||
|
||||
> 仅描述「平台管理员需要能完成哪些业务操作」;不定义具体 RESTful 路径、HTTP 方法、参数结构。具体接口设计见对应技术方案文档。
|
||||
|
||||
#### 5.5.1 租户管理
|
||||
|
||||
- 平台管理员需要能查询租户列表(支持多维度筛选)
|
||||
- 平台管理员需要能查看单租户的完整详情(基本信息、套餐、用户、License、备份、操作历史)
|
||||
- 平台管理员需要能创建新租户(含异步初始化 Schema 与默认配置)
|
||||
- 平台管理员需要能编辑租户基本信息(公司名、联系人、邮箱、地区)
|
||||
- 平台管理员需要能挂起 / 恢复租户(含挂起原因、到期时间)
|
||||
- 平台管理员需要能软删除 / 硬删除租户(硬删除需 MFA)
|
||||
- 平台管理员需要能撤销软删除(冷静期内)
|
||||
- 平台管理员需要能调整租户的 License 到期日期
|
||||
- 平台管理员需要能调整租户的 License 授权用户数上限
|
||||
- 平台管理员需要能升级租户套餐
|
||||
- 平台管理员需要能下载租户的「入驻信息 PDF」
|
||||
|
||||
#### 5.5.2 租户用户管理
|
||||
|
||||
- 平台管理员需要能查询租户内的全部用户
|
||||
- 平台管理员需要能新增 / 替换 / 撤销 Tenant Admin
|
||||
- 平台管理员需要能为租户内任意用户重置密码(链接 / 临时密码两种方式)
|
||||
|
||||
#### 5.5.3 数据导出与备份
|
||||
|
||||
- 平台管理员需要能为指定租户触发数据导出(异步,可查询任务状态、获取下载链接)
|
||||
- 平台管理员需要能为指定租户手动触发完整备份
|
||||
- 平台管理员需要能查询某租户的备份记录列表
|
||||
- 平台管理员需要能基于某个备份执行恢复操作(需 MFA)
|
||||
- 平台管理员需要能配置全局 / 单租户的定时备份策略
|
||||
|
||||
#### 5.5.4 平台版本与升级
|
||||
|
||||
- 平台管理员需要能上传 / 拉取系统升级包
|
||||
- 平台管理员需要能配置升级策略(全量 / 灰度,含内测租户名单)
|
||||
- 平台管理员需要能触发升级,并实时查询升级进度(租户维度)
|
||||
- 平台管理员需要能查看升级日志
|
||||
- 平台管理员需要能触发升级回滚(全量 / 单租户,需 MFA)
|
||||
- 平台管理员需要能查询「平台基础数据版本」与「各租户数据升级版本」总览
|
||||
|
||||
#### 5.5.5 客户端发布
|
||||
|
||||
- 平台管理员需要能查询客户端版本列表(含状态、下载量)
|
||||
- 平台管理员需要能新增客户端版本(上传安装包,系统自动计算 SHA256)
|
||||
- 平台管理员需要能修改某版本元数据(更新日志、版本类型、最低兼容版本等)
|
||||
- 平台管理员需要能切换某版本状态(草稿 → 已发布 / 已发布 → 已下线)
|
||||
- 平台管理员需要能将某历史版本回滚为「已发布」(同时把当前版本置为已下线)
|
||||
- 平台管理员需要能对指定版本范围的客户端打上「强制更新」标记
|
||||
- 平台管理员需要能查询全平台客户端版本分布(饼图、趋势图)
|
||||
- 平台管理员需要能查询全平台租户活跃榜(活跃安装数、历史装机总数)
|
||||
- 平台管理员需要能查询任一租户的客户端版本分布与活跃数
|
||||
|
||||
> 客户端**自身**与更新服务的交互(如查询最新版本、上报心跳)属于客户端运行时与平台之间的接口,不属于平台管理员的操作;本 PRD 不在此章描述,由 `TECH_STACK/平台管理后台技术方案.md` 定义。
|
||||
|
||||
#### 5.5.6 监控与告警
|
||||
|
||||
- 平台管理员需要能查询全局 / 单租户的监控图表
|
||||
- 平台管理员需要能配置告警规则(指标 + 阈值 + 通知渠道)
|
||||
- 平台管理员需要能查询告警历史
|
||||
|
||||
#### 5.5.7 审计日志
|
||||
|
||||
- 平台管理员(含审计员)需要能按多维度筛选审计日志
|
||||
- 平台管理员(含审计员)需要能导出筛选结果为 CSV
|
||||
|
||||
#### 5.5.8 平台管理员账号与安全
|
||||
|
||||
- Platform Admin 需要能创建 / 编辑 / 停用平台管理员账号
|
||||
- Platform Admin 需要能配置管理员角色(Platform Admin / 运营人员 / 只读审计员)
|
||||
- 全部平台管理员需要能首次登录时配置 MFA(无法跳过)
|
||||
- 全部平台管理员需要能在高危操作时通过 MFA 二次确认
|
||||
- Platform Admin 需要能配置 IP 白名单
|
||||
- Platform Admin 需要能查看活跃会话并强制登出指定管理员
|
||||
|
||||
---
|
||||
|
||||
### 5.6 安全与访问控制
|
||||
|
||||
**强制要求(不可降级)**:
|
||||
|
||||
| 安全要求 | 说明 |
|
||||
|---------|------|
|
||||
| MFA 强制启用 | 所有管理员账号首次登录强制配置 TOTP;不可跳过 |
|
||||
| IP 白名单 | 仅允许指定 IP 范围访问平台管理后台 |
|
||||
| 高危操作二次验证 | 删除租户、数据恢复、系统回滚、客户端版本下线、强制更新推送均触发 MFA 二次确认 |
|
||||
| 会话超时 | 无操作 30 分钟自动登出,Token 失效 |
|
||||
| 强制登出 | Platform Admin 可在「管理员设置」中强制终止指定管理员的所有会话 |
|
||||
| 与租户应用隔离 | 平台管理后台部署在独立平台域名,不与租户应用共享 Session / Cookie |
|
||||
|
||||
### 5.7 操作审计日志规范
|
||||
|
||||
所有写操作(Create / Update / Delete)及高危操作必须落审计日志,字段:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "UUID",
|
||||
"operator_id": "管理员用户 ID",
|
||||
"operator_name": "管理员显示名",
|
||||
"action_type": "CREATE_TENANT | SUSPEND_TENANT | RESUME_TENANT | DELETE_TENANT | HARD_DELETE_TENANT | RESTORE_DATA | SYSTEM_UPGRADE | ROLLBACK | RESET_PASSWORD | RELEASE_CLIENT_VERSION | OFFLINE_CLIENT_VERSION | FORCE_UPDATE_PUSH | UPDATE_LICENSE | UPDATE_LICENSE_USER_LIMIT | AUTO_SUSPEND_LICENSE_EXPIRED | ...",
|
||||
"target_type": "Tenant | User | System | Backup | ClientRelease | Admin",
|
||||
"target_id": "操作对象 ID",
|
||||
"target_name": "操作对象可读名称",
|
||||
"payload_summary": "操作内容摘要(非敏感字段)",
|
||||
"result": "SUCCESS | FAILED",
|
||||
"error_message": "失败原因(如有)",
|
||||
"ip_address": "操作来源 IP",
|
||||
"created_at": "ISO 8601 时间戳"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 角色权限矩阵
|
||||
|
||||
| 操作 | Platform Admin | 运营人员 | 只读审计员 |
|
||||
|------|---------------|---------|-----------|
|
||||
| 创建租户 | ✅ | ✅ | ❌ |
|
||||
| 挂起 / 恢复租户 | ✅ | ✅ | ❌ |
|
||||
| 软删除租户 | ✅ | ✅ | ❌ |
|
||||
| 硬删除租户 | ✅ | ❌ | ❌ |
|
||||
| 调整 License 到期日期 / 用户数上限 | ✅ | ✅ | ❌ |
|
||||
| 数据导出 | ✅ | ✅ | ❌ |
|
||||
| 手动触发备份 | ✅ | ✅ | ❌ |
|
||||
| 数据恢复 | ✅ | ❌ | ❌ |
|
||||
| 系统升级 | ✅ | ❌ | ❌ |
|
||||
| 系统回滚 | ✅ | ❌ | ❌ |
|
||||
| 查看版本总览 | ✅ | ✅ | ❌ |
|
||||
| 配置告警规则 | ✅ | ✅ | ❌ |
|
||||
| 发布 / 下线客户端版本 | ✅ | ❌ | ❌ |
|
||||
| 客户端版本回滚 | ✅ | ❌ | ❌ |
|
||||
| 推送强制更新标记 | ✅ | ❌ | ❌ |
|
||||
| 查看客户端版本分布与活跃榜 | ✅ | ✅ | ✅ |
|
||||
| 查看审计日志 | ✅ | ✅ | ✅ |
|
||||
| 导出审计日志 | ✅ | ✅ | ✅ |
|
||||
| 管理员账号管理 | ✅ | ❌ | ❌ |
|
||||
| 强制登出管理员 | ✅ | ❌ | ❌ |
|
||||
| 配置 IP 白名单 | ✅ | ❌ | ❌ |
|
||||
|
||||
---
|
||||
|
||||
## 7. 租户状态机
|
||||
|
||||
```
|
||||
[新建中 Creating]
|
||||
↓ 成功
|
||||
[活跃 Active] ←──────────────────┐
|
||||
↓ 手动 / License 到期挂起 │ 到期自动恢复(仅手动挂起且设置了到期时间)/ 手动恢复
|
||||
[已挂起 Suspended] ───────────────┘
|
||||
↓ 删除操作(软删除)
|
||||
[待清除 Pending Delete](冷静期 30 天)
|
||||
↓ 冷静期到期 / 硬删除
|
||||
[已删除 Deleted]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 不构建清单(What We're NOT Building)
|
||||
|
||||
| 请求/功能 | 原因 | 重新评估条件 |
|
||||
|----------|------|------------|
|
||||
| 自动化账单与发票 | 财务模块独立立项 | 财务模块 PRD 完成后接入 |
|
||||
| 租户端自助迁移工具 | 当前规模不需要 | 租户数 > 500 时重新评估 |
|
||||
| 平台管理后台移动端 | 运营场景明确为 PC | v2 规划,用户调研支持时推进 |
|
||||
| Webhook 事件推送市场 | 集成复杂度高,无客户驱动 | 有 3+ 客户明确需求时评估 |
|
||||
| 多语言管理界面 | 内部团队中文已满足 | 国际化扩张时规划 |
|
||||
| macOS / Linux 客户端 | 99% 用户为 Windows | 市场需求出现时评估 |
|
||||
| 移动端客户端 App | v2 规划 | v2 启动时 |
|
||||
| 客户端离线模式 | 联网使用为既定形态 | 暂不考虑 |
|
||||
| 客户端代码混淆 / 反逆向 | 优先功能交付 | 安全审计要求时启动 |
|
||||
| 响应客户数据导出请求 | 暂缓 | 后续迭代排期时细化 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 发布计划
|
||||
|
||||
| 阶段 | 时间 | 范围 | 通过标准 |
|
||||
|------|------|------|---------|
|
||||
| 内部 Alpha | Week 1–4 | 平台内部团队 | 核心租户 CRUD 流程无 P0 Bug;MFA 可用;客户端发布流程闭环 |
|
||||
| 封闭 Beta | Week 5–6 | 运营团队日常使用 + 1 家种子客户的客户端 | 备份/恢复完整可用;审计日志 100% 覆盖;客户端自动更新成功率 ≥ 95% |
|
||||
| 正式上线 | Week 7 | 全量运营团队 + 全部客户的客户端 | 升级/回滚验证通过;监控告警规则配置完成;客户端版本一致性 ≥ 95% |
|
||||
|
||||
**回滚标准**:
|
||||
- 正式上线 72 小时内发现租户数据隔离漏洞或审计日志丢失 → 立即回滚平台管理后台
|
||||
- 客户端版本上线 24 小时内:自动更新失败率 > 5%、白屏 / 崩溃率 > 2%、或收到 P0 安全报告 → 立即下线该版本并恢复上一稳定版本
|
||||
|
||||
---
|
||||
|
||||
## 10. 技术考量(指引性)
|
||||
|
||||
> 本节为产品视角对技术决策的影响概述,详细方案请见各技术文档。
|
||||
|
||||
| 维度 | 关键依赖 | 备注 |
|
||||
|------|---------|------|
|
||||
| 多租户隔离 | `django-tenants` | 平台管理后台数据落 `public` schema,跨租户查询走 `public` 维度 |
|
||||
| 异步任务 | Celery + Celery Beat | 创建租户、备份、导出、定时挂起检查等 |
|
||||
| 数据库备份 | PostgreSQL `pg_dump`(待评估流式方案) | 大租户备份耗时风险 |
|
||||
| 文件存储 | Cloudflare R2 | 备份、导出包、客户端安装包 |
|
||||
| 监控 | Sentry + Grafana | 已在技术栈中规划 |
|
||||
| MFA | `django-otp` + TOTP | 待最终选型 |
|
||||
| 客户端 | Electron + electron-updater | 见 `TECH_STACK/平台管理后台技术方案.md` |
|
||||
| 客户端心跳/活跃统计 | `public.client_heartbeats`(Upsert + 24h 活跃口径,见 `ADR-20260430-007`) | 是租户活跃榜与版本分布的数据源 |
|
||||
| 客户端 API 命名空间 | 统一 `/api/release/...`(见 `ADR-20260430-009`) | 与租户客源管理 `apps/client/` 命名空间隔离 |
|
||||
|
||||
### 待解决问题(开发启动前必须确认)
|
||||
|
||||
- [ ] 数据库备份方案:`pg_dump` 直接执行还是基于 WAL 的增量备份(如 pgBackRest)?— Owner: 工程负责人
|
||||
- [ ] 监控数据来源:Grafana 直接对接 PostgreSQL 还是通过 Prometheus Exporter?— Owner: 运维团队
|
||||
- [ ] MFA 库选型:`django-otp` + TOTP 还是集成第三方认证?— Owner: 工程负责人
|
||||
- [ ] 审计日志存储:写入 `public` schema 还是独立日志服务(如 Elasticsearch)?— Owner: 工程负责人
|
||||
- [ ] 客户端 EV 代码签名证书采购主体与预算 — Owner: IT 负责人
|
||||
- [ ] CI/CD 平台选型(客户端构建签名流水线)— Owner: 运维负责人
|
||||
- [ ] 客户端便携版(Portable ZIP)是否纳入 v1 — Owner: PM
|
||||
- [ ] 客户端启动时租户 URL 分发方式(统一域名重定向 vs 内置配置文件)— Owner: 产品 + 工程
|
||||
|
||||
---
|
||||
|
||||
## 11. 附录
|
||||
|
||||
### 11.1 术语表
|
||||
|
||||
| 术语 | 定义 |
|
||||
|------|------|
|
||||
| Platform Admin | 平台超级管理员,拥有所有高危操作权限 |
|
||||
| 运营人员 | 平台日常运营,承担租户管理、监控巡检 |
|
||||
| 只读审计员 | 仅查询与导出审计日志,无写权限 |
|
||||
| Tenant Admin | 租户内的最高权限用户,**对平台管理后台无访问权限** |
|
||||
| Tenant Code | 租户唯一可读短码,用作租户访问 URL 中的 `tenant=` 参数 |
|
||||
| 灰度升级 | 先对内测租户升级、验证通过后再全量推送 |
|
||||
| 数据导出 | 输出结构化数据 + 文件 CDN URL 清单,分钟级,不含文件实体 |
|
||||
| 完整备份 | 数据库 + 文件实体的完整副本,小时级,用于灾难恢复与租户迁移 |
|
||||
| SemVer | 语义化版本控制 `主.次.补丁` |
|
||||
| EV 证书 | Extended Validation 代码签名证书 |
|
||||
| SHA256 | 用于校验客户端安装包完整性的散列算法 |
|
||||
|
||||
### 11.2 关联文档
|
||||
|
||||
| 类型 | 文档 |
|
||||
| ------------------ | ----------------------------------------- |
|
||||
| 项目入口 | `README.md` |
|
||||
| 开发约束 | `AGENTS.md` |
|
||||
| MVP 范围 | `PRD/PRD_MVP.md` |
|
||||
| 客户端技术方案 | `TECH_STACK/平台管理后台技术方案.md` |
|
||||
| Public Schema 数据模型 | `DATA_MODEL/DATA_MODEL_PUBLIC.md` |
|
||||
| ADR | `ADR.md`(含 `ADR-20260502-001`:本 PRD 合并决策) |
|
||||
@@ -2,17 +2,27 @@
|
||||
|
||||
**状态**: Draft
|
||||
**作者**: 产品经理
|
||||
**最后更新**: 2026-04-30(v2.0 根据 review 后的 §4 用户故事全面同步 §5 功能详细说明:删除找回用户名流程及邮件模板;找回密码改为纯短信流程;新增 §5.5 手机验证码登录详细说明;§6 技术注意事项更新短信依赖/风险/开放问题;§8.2 接口清单同步正式功能状态)
|
||||
**版本**: 2.0
|
||||
**最后更新**: 2026-05-02(v3.0 按 `ADR-20260502-003` 重写:剥离全部实现细节——具体 API 路径、HTTP 方法、JSON Schema、Redis Key、字段类型、Electron API 名、Cookie 属性、限流接口实现等——交由 Tech / DATA_MODEL 承接;本文件只保留业务能力、页面与导航、业务规则、状态机、验收标准)
|
||||
**版本**: 3.0
|
||||
**所属系统**: Fonrey 房产经纪管理系统
|
||||
**关联模块**: 组织人事管理、权限管理、系统管理
|
||||
**关联模块**: 组织人事管理、权限管理、平台管理后台
|
||||
|
||||
## 关联文档(实现口径)
|
||||
|
||||
- 实现细节(端点路径、HTTP 方法、JSON Schema、错误码、滑块/OTP 算法、限流策略、Electron 客户端约定):`TECH_STACK/登录管理技术方案.md`(v4.1)
|
||||
- 数据结构(账号表、登录审计表、短信 OTP 表、历史密码表、Redis Key 命名、字段类型与索引):`DATA_MODEL/DATA_MODEL_LOGIN.md`
|
||||
- 全局 API 契约(统一错误响应、分页、限流外显规范):`TECH_STACK/API_CONTRACT.md`
|
||||
- 测试用例:`TEST_CASES/TEST_CASES_LOGIN_MODULE.md`
|
||||
|
||||
> 本 PRD 涉及的"具体路径 / 字段名 / Token TTL 数值 / Cookie 属性 / Redis Key / 框架 API 名"等实现口径,**均不在本文件出现**,请按上表查阅对应权威文档。
|
||||
|
||||
## 变更历史
|
||||
|
||||
| 版本 | 日期 | 作者 | 变更说明 |
|
||||
|------|------|------|---------|
|
||||
| v1.x | — | 产品经理 | 初稿至 v1.9(详见 git 历史) |
|
||||
| 版本 | 日期 | 作者 | 变更说明 |
|
||||
| ---- | ---------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| v1.x | — | 产品经理 | 初稿至 v1.9(详见 git 历史) |
|
||||
| v2.0 | 2026-04-30 | 产品经理 | 根据 review 后的 §4 用户故事全面同步 §5 功能详细说明:删除找回用户名流程及邮件模板;找回密码改为纯短信流程;新增 §5.5 手机验证码登录详细说明;§6 技术注意事项更新短信依赖/风险/开放问题;§8.2 接口清单同步正式功能状态;全文「Tenant ID」对外概念统一替换为「Tenant Code」 |
|
||||
| v3.0 | 2026-05-02 | Sisyphus | 按 `ADR-20260502-003` 重写:剥离全部实现细节交由 Tech / DATA_MODEL 承接;删除 §5.1.4 接口规范代码块、§5.2.2 Redis Key 与传输层细节、§5.3.3 字段类型表、§5.6 数据模型字段清单、§5.7 Electron 客户端约定、§6.1 依赖技术选型表、§6.2 多租户实现细节、§8.2 接口清单汇总;保留页面/导航/业务规则/状态机/验收标准;具体口径全部以 `TECH_STACK/登录管理技术方案.md` 为准 |
|
||||
|
||||
|
||||
---
|
||||
@@ -21,14 +31,14 @@
|
||||
|
||||
### 1.1 背景
|
||||
|
||||
Fonrey 是一套面向房产经纪公司的 B2B SaaS 平台,采用多租户架构(`django-tenants` + PostgreSQL Schema 隔离)。终端用户通过 **Windows 桌面客户端(Electron)** 使用系统,无需手动输入网址即可打开 Web 应用。
|
||||
Fonrey 是一套面向房产经纪公司的 B2B SaaS 平台,采用多租户架构,每家经纪公司是一个独立租户。终端用户通过 **Windows 桌面客户端(Electron 壳应用)** 使用系统,无需手动输入网址即可打开 Web 应用。
|
||||
|
||||
在多租户环境下,用户的身份验证流程比单租户系统更复杂:
|
||||
|
||||
- 用户安装客户端后,系统必须先识别当前设备归属哪个租户,才能加载对应租户的登录界面和数据隔离环境
|
||||
- 每家经纪公司作为独立租户,其员工账号、组织结构、数据均完全隔离
|
||||
- 经纪人账号须与实名员工档案绑定,确保每一条操作记录可追溯至具体自然人
|
||||
- 现阶段登录方式以账号密码为主;手机验证码登录、微信扫码登录需预留接口,待移动端(小程序)上线后实现
|
||||
- 现阶段登录方式以账号密码与手机验证码为主;微信扫码登录需预留入口,待移动端(小程序)上线后实现
|
||||
|
||||
### 1.2 核心痛点
|
||||
|
||||
@@ -36,7 +46,7 @@ Fonrey 是一套面向房产经纪公司的 B2B SaaS 平台,采用多租户架
|
||||
|------|--------|---------|
|
||||
| 多租户环境下,客户端不知道应该连接哪个租户的服务端 | 新用户首次安装后无法正常使用 | 系统无法启动,用户体验极差 |
|
||||
| 账号密码裸露登录,缺乏验证码保护 | 所有用户 | 存在暴力破解、自动化恶意登录风险 |
|
||||
| 用户忘记账号或密码无自助找回通道 | Agent(经纪人) | 依赖管理员手动重置,效率低 |
|
||||
| 用户忘记密码无自助找回通道 | Agent(经纪人) | 依赖管理员手动重置,效率低 |
|
||||
| 账号未与实名经纪人档案绑定 | Tenant Admin(租户管理员)、合规审计 | 操作行为无法追溯至自然人 |
|
||||
| 无多因素认证,安全系数低 | 管理层、数据合规 | 存在账号冒用、数据泄露风险 |
|
||||
|
||||
@@ -56,45 +66,97 @@ Fonrey 是一套面向房产经纪公司的 B2B SaaS 平台,采用多租户架
|
||||
| 目标 | 指标 | 当前基准 | 目标值 | 衡量周期 |
|
||||
|------|------|----------|--------|----------|
|
||||
| 降低登录失败率 | 账号密码正确情况下的登录成功率 | 待统计 | ≥ 99% | 上线后 30 天 |
|
||||
| 防止恶意登录 | 每日验证码拦截异常登录请求数 | 0(无保护) | 建立基线,同IP异常次数 > 5次/分钟触发封锁 | 上线后持续监控 |
|
||||
| 提升找回账号效率 | 用户自助找回密码耗时 | 依赖管理员(约1工作日) | < 3 分钟(短信验证码自助) | 上线后 30 天 |
|
||||
| 防止恶意登录 | 每日验证码拦截异常登录请求数 | 0(无保护) | 建立基线,对同 IP 异常突增触发封锁 | 上线后持续监控 |
|
||||
| 提升找回账号效率 | 用户自助找回密码耗时 | 依赖管理员(约 1 工作日) | < 3 分钟(短信验证码自助) | 上线后 30 天 |
|
||||
| 确保账号实名绑定率 | 拥有系统账号且未与员工档案绑定的账号比例 | 待统计 | 0%(强制绑定) | 上线即达标 |
|
||||
| Tenant 识别成功率 | 首次安装后成功完成 Tenant 识别的用户比例 | 待统计 | ≥ 98% | 上线后 30 天 |
|
||||
|
||||
> 具体的同 IP 限流阈值与 Tenant Code 校验频控数值,详见 `TECH_STACK/登录管理技术方案.md`。
|
||||
|
||||
---
|
||||
|
||||
## 3. 非目标(本期不做)
|
||||
|
||||
- **手机验证码登录**:移动端小程序上线后实现,本期**接口预留**,UI 入口以「即将开放」禁用态展示
|
||||
> **注意**:本条已更新。手机验证码登录已升级为 **MVP 正式功能**(见 Story 5),与密码登录并列提供。此非目标条目保留仅作版本记录,已失效。
|
||||
- **微信扫码登录**:移动端小程序上线后实现,本期**接口预留**,UI 入口以「即将开放」禁用态展示
|
||||
- **微信扫码登录**:移动端小程序上线后实现,本期**仅在登录页保留禁用入口**,不开放实际功能
|
||||
- **单点登录(SSO)/ 企业微信集成**:后续版本规划
|
||||
- **多设备并发登录的强制踢出策略**:本期允许同账号多端登录,后续安全策略模块规划
|
||||
- **登录时段限制 / IP 白名单**:安全策略模块另行规划
|
||||
- **管理后台(Platform Admin)登录**:Tenant Admin(租户管理员)登录管理后台的流程属于系统管理模块,本 PRD 专注租户内用户登录
|
||||
- **平台管理后台(Platform Admin)登录**:属于平台管理后台模块,本 PRD 专注租户内用户登录
|
||||
- **找回用户名流程**:普通员工用户名固定为手机号,无需找回;Tenant Admin 如忘记用户名请联系平台运营线下处理(原 Story 4 已废弃)
|
||||
|
||||
---
|
||||
|
||||
## 4. 用户故事与验收标准
|
||||
## 4. 页面清单与导航
|
||||
|
||||
> 本节描述用户视角的页面与跳转关系;具体的前端路由实现与 URL 形态由 `TECH_STACK/登录管理技术方案.md` 定义。
|
||||
|
||||
### 4.1 页面清单
|
||||
|
||||
| 页面 | 访问权限 | 用途 |
|
||||
|---|---|---|
|
||||
| Tenant 识别页 | 公开(无需登录) | 客户端首次启动或切换公司时输入租户识别码 |
|
||||
| 登录页 | 公开(需先完成 Tenant 识别) | 提供「密码登录」/「验证码登录」两种方式,含微信扫码禁用入口 |
|
||||
| 找回密码页(三步) | 公开 | 输入手机号 → 输入短信验证码 → 设置新密码 |
|
||||
| 首次登录强制改密页 | 已登录且账号处于初始密码状态 | 强制用户修改初始密码后方可使用系统 |
|
||||
| 系统首页 | 已登录且非初始密码状态 | 业务入口;不在本 PRD 范围 |
|
||||
|
||||
### 4.2 导航流程
|
||||
|
||||
```
|
||||
[客户端启动]
|
||||
│
|
||||
├─ 本地无 Tenant 缓存 ──→ [Tenant 识别页]
|
||||
│ │ 验证成功
|
||||
│ ↓
|
||||
│ 缓存 Tenant ──→ [登录页]
|
||||
│
|
||||
└─ 本地有 Tenant 缓存 ──→ [登录页]
|
||||
|
||||
[登录页]
|
||||
│
|
||||
├─ 密码 / 验证码登录成功
|
||||
│ │
|
||||
│ ├─ 账号为"初始密码"状态 ──→ [首次登录强制改密页] ──改密成功──→ [系统首页]
|
||||
│ └─ 账号为"非初始密码"状态 ──→ [系统首页]
|
||||
│
|
||||
├─ 点击"忘记密码" ──→ [找回密码页(步骤一)] → [步骤二] → [步骤三] ──→ 回 [登录页]
|
||||
│
|
||||
└─ 点击"切换公司"(二次确认)──→ 清缓存 ──→ [Tenant 识别页]
|
||||
|
||||
[系统内]
|
||||
│
|
||||
├─ 主动登出 ──→ [登录页]
|
||||
├─ Session 过期 ──→ [登录页](提示"登录已过期,请重新登录")
|
||||
└─ 客户端版本过低 ──→ [更新提示页] → 阻断后续登录流程
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 用户故事与验收标准
|
||||
|
||||
### Story 1:新用户首次启动客户端——Tenant 识别
|
||||
|
||||
**As** 新安装 Fonrey 客户端的经纪人,**I want** 在首次启动时输入所属公司的 12位 Tenant Code 完成租户识别,**So that** 客户端能连接到正确的服务端,后续显示对应公司的登录界面和数据。
|
||||
**As** 新安装 Fonrey 客户端的经纪人,**I want** 在首次启动时输入所属公司的 12 位 Tenant Code 完成租户识别,**So that** 客户端能连接到正确的服务端,后续显示对应公司的登录界面和数据。
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- [ ] 客户端首次启动时(本地无 Tenant Code 缓存),自动呈现「Tenant 识别」界面,而非直接显示登录界面
|
||||
- [ ] 界面包含:产品 Logo、产品名称「Fonrey 房睿」、说明文案「请输入您公司的专属识别码」、Tenant Code 输入框、「确认」按钮
|
||||
- [ ] Tenant Code 输入框支持粘贴操作,自动去除前后空格
|
||||
- [ ] 点击「确认」后,客户端向服务端发起 Tenant 验证请求(`POST /api/auth/tenant/verify/`),展示加载状态(spinner)
|
||||
- [ ] **验证成功**:服务端返回租户名称及品牌信息(如公司名称、Logo URL);客户端将 Tenant Code 写入本地持久化存储,自动跳转至该租户的登录界面;界面顶部展示「正在登录:XX 房产」
|
||||
- [ ] **验证失败(Tenant Code 无效)**:输入框下方显示红色错误提示「识别码无效,请联系您的Tenant Admin(租户管理员)获取正确的识别码」;Tenant Code 不写入本地缓存;用户可重新输入
|
||||
- [ ] 客户端首次启动时(本地无 Tenant Code 缓存),自动呈现「Tenant 识别」页面,而非直接显示登录页
|
||||
- [ ] 页面包含:产品 Logo、产品名称「Fonrey 房睿」、说明文案「请输入您公司的专属识别码」、Tenant Code 输入框、「确认」按钮、帮助文案「不知道识别码?请联系您公司的Tenant Admin(租户管理员)」
|
||||
- [ ] Tenant Code 输入框支持粘贴操作,自动去除前后空格,仅接受数字字符(非数字自动过滤),固定 12 位
|
||||
- [ ] 点击「确认」后展示加载状态(spinner),由客户端向服务端发起 Tenant 验证
|
||||
- [ ] **验证成功**:服务端返回租户名称及品牌信息(公司名称、Logo 等);客户端将 Tenant Code 持久化到本地(必须加密存储),自动跳转至该租户的登录页;登录页顶部展示「正在登录:XX 房产」
|
||||
- [ ] **验证失败**(识别码无效):输入框下方显示红色错误提示「识别码无效,请联系您的 Tenant Admin(租户管理员)获取正确的识别码」;Tenant Code 不写入本地缓存;用户可重新输入
|
||||
- [ ] **网络异常**:显示「网络连接失败,请检查网络后重试」,提供「重试」按钮
|
||||
- [ ] 非首次启动(本地已有合法 Tenant Code 缓存):直接跳过识别界面,进入登录界面
|
||||
- [ ] 登录界面提供「切换公司」入口(链接文字,非主要 CTA),点击后清除本地 Tenant Code 缓存并重新显示 Tenant 识别界面;确认前弹出二次确认「切换公司将退出当前账号,是否继续?」
|
||||
- [ ] Tenant 验证接口属于公开接口,无需鉴权;但需对单 IP 请求频率限制(每分钟 ≤ 10 次)以防止枚举攻击
|
||||
- [ ] 非首次启动(本地已有合法 Tenant Code 缓存):直接跳过识别页,进入登录页
|
||||
- [ ] 登录页提供「切换公司」入口(链接文字,非主要 CTA),点击后弹出二次确认「切换公司将退出当前账号,是否继续?」,确认后清除本地 Tenant Code 缓存并重新显示 Tenant 识别页
|
||||
- [ ] Tenant 验证为公开操作,无需登录态,但平台需对该接口做防枚举的频控保护(具体阈值见 Tech 文档)
|
||||
|
||||
**Tenant Code 业务规则**:
|
||||
|
||||
- 格式:12 位纯数字
|
||||
- 生成:由平台运营在平台管理后台开通租户时自动生成,全局唯一,不允许手动指定
|
||||
- 唯一性:全局唯一,同一 Tenant Code 不得分配给多个租户
|
||||
- 客户端存储:必须加密落盘,禁止明文(实现细节见 Tech 文档 §十三 Electron 客户端约定)
|
||||
|
||||
---
|
||||
|
||||
@@ -102,35 +164,38 @@ Fonrey 是一套面向房产经纪公司的 B2B SaaS 平台,采用多租户架
|
||||
|
||||
**As** 已识别租户的经纪人,**I want** 通过手机号和密码完成登录,**So that** 进入系统开始工作。
|
||||
|
||||
> **说明**:普通员工的登录账号即为其手机号(由Tenant Admin(租户管理员)在新增员工时自动创建),无需记忆额外用户名。Tenant Admin 账号的登录名为平台运营自定义字符串,不受此约束。
|
||||
> **说明**:普通员工的登录账号即为其手机号(由 Tenant Admin 在新增员工时自动创建),无需记忆额外用户名。Tenant Admin 账号的登录名为该租户联系人手机号,规则一致。
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- [ ] 登录界面展示:租户品牌标识(公司 Logo + 公司名称)、手机号输入框、密码输入框、滑块拼图验证区域、「登录」按钮
|
||||
- [ ] 登录页展示:租户品牌标识(公司 Logo + 公司名称)、登录方式 Tab(「密码登录」/「验证码登录」,默认选中「密码登录」)、手机号输入框、密码输入框、滑块拼图验证区域、「登录」按钮、「忘记密码」链接、「切换公司」入口、微信扫码禁用入口
|
||||
- [ ] 手机号输入框 Placeholder:「请输入您的手机号」;仅接受数字字符(非数字自动过滤),固定 11 位
|
||||
- [ ] 密码输入框默认密文显示,右侧提供「显示/隐藏」图标切换明密文
|
||||
- [ ] **行为验证码(滑块拼图)**:展示一张带缺口的背景图和一块可拖动的拼图碎片,用户通过拖动滑块将碎片移动至缺口位置完成验证;无需输入任何字符,操作直观快速
|
||||
- [ ] 验证逻辑:前端记录滑动轨迹(坐标序列 + 耗时),与背景图缺口位置一同发送至服务端;服务端综合校验**位置偏差**(允许 ±5px 容差)和**轨迹特征**(是否存在人类滑动的加速/减速规律)以区分机器行为
|
||||
- [ ] 验证失败(位置不准或轨迹异常):拼图区域抖动动画提示失败,自动刷新新的背景图,用户重新拖动;**不计入账号密码错误次数**
|
||||
- [ ] **行为验证码(滑块拼图)**:展示一张带缺口的背景图和一块可拖动的拼图碎片,用户通过拖动滑块将碎片移动至缺口位置完成验证;无需输入任何字符
|
||||
- [ ] 验证失败(位置不准或轨迹异常):拼图区域抖动提示,自动刷新新背景图,用户重新拖动;**不计入账号密码错误次数**
|
||||
- [ ] 验证成功后,拼图区域显示绿色对勾 + 「验证通过」文案,状态持续至本次登录提交完成
|
||||
- [ ] 提供「刷新」图标按钮,允许用户主动刷新背景图(针对图片模糊或缺口不清晰的情况)
|
||||
- [ ] 背景图从预置图库中随机抽取,缺口位置每次随机生成,防止固定模式被预测
|
||||
- [ ] 三项(手机号、密码、验证码)均有填写后,「登录」按钮才可点击(否则置灰)
|
||||
- [ ] 提供「刷新」图标按钮,允许用户主动刷新背景图
|
||||
- [ ] 三项(手机号、密码、滑块)均完成后,「登录」按钮才可点击(否则置灰)
|
||||
- [ ] 点击「登录」触发前端格式校验:
|
||||
- 手机号为空 → 输入框下方红色提示「请输入手机号」
|
||||
- 手机号为空 → 提示「请输入手机号」
|
||||
- 手机号不满 11 位 → 提示「请输入完整的 11 位手机号」
|
||||
- 密码为空 → 提示「请输入密码」
|
||||
- 验证码为空 → 提示「请完成滑块验证」
|
||||
- [ ] 格式校验通过后,向服务端发起登录请求,按钮进入 loading 状态防止重复提交
|
||||
- [ ] **登录成功(常规)**:服务端返回 Session Token 及 `is_initial_password` 标记;客户端存储 Token;
|
||||
- 若 `is_initial_password = False`:直接跳转系统首页,顶部显示欢迎信息「欢迎回来,{姓名}」
|
||||
- 若 `is_initial_password = True`:**立即跳转「修改初始密码」强制页面**,不可关闭、不可跳过、不可访问任何其他功能页面(详见 §5.3.4)
|
||||
- [ ] **登录失败(手机号或密码错误)**:显示「手机号或密码错误,请重新输入」(不区分具体原因,防止枚举攻击);验证码自动刷新;密码输入框清空;手机号保留
|
||||
- [ ] **登录失败(验证码错误)**:显示「验证码有误,请重新输入」;验证码自动刷新;验证码输入框清空
|
||||
- [ ] **账号被锁定**(同一账号密码连续错误 ≥ 5 次):显示「账号已被临时锁定,请 30 分钟后重试,或联系管理员解锁」;锁定状态下「登录」按钮置灰
|
||||
- 滑块未完成 → 提示「请完成滑块验证」
|
||||
- [ ] 格式校验通过后提交登录,按钮进入 loading 状态防止重复提交
|
||||
- [ ] **登录成功**:
|
||||
- 若账号处于"非初始密码"状态:直接进入系统首页,顶部显示欢迎信息「欢迎回来,{姓名}」
|
||||
- 若账号处于"初始密码"状态:**立即跳转至「首次登录强制改密页」**,不可关闭、不可跳过、不可访问其他功能页面(详见 §6.4)
|
||||
- [ ] **登录失败(手机号或密码错误)**:显示「手机号或密码错误,请重新输入」(不区分具体原因,防止枚举攻击);滑块自动刷新;密码输入框清空;手机号保留
|
||||
- [ ] **登录失败(滑块异常)**:显示「验证码有误,请重新输入」;滑块自动刷新
|
||||
- [ ] **账号被锁定**(同一账号密码连续错误达到上限):显示「账号已被临时锁定,请稍后再试,或联系管理员解锁」;锁定状态下「登录」按钮置灰
|
||||
- [ ] **账号已停用**:显示「账号已停用,请联系您的管理员」
|
||||
- [ ] **Session 过期**:用户在系统内操作时 Session 过期,自动跳转至登录界面,并提示「登录已过期,请重新登录」
|
||||
- [ ] 登录界面底部提供:「忘记密码」链接(详见 Story 3);移除「忘记用户名」入口(普通员工用户名即手机号,无需找回;Tenant Admin 如忘记用户名请联系平台运营)
|
||||
- [ ] **Session 过期**:用户在系统内操作时 Session 过期,自动跳转至登录页,并提示「登录已过期,请重新登录」
|
||||
|
||||
**业务规则**(具体数值口径见 Tech 文档):
|
||||
|
||||
- 同一账号密码连续错误达到上限后,账号进入临时锁定状态,到期自动解锁;管理员可手动解锁
|
||||
- 滑块验证失败不计入密码错误次数
|
||||
- 所有登录请求强制 HTTPS
|
||||
|
||||
---
|
||||
|
||||
@@ -138,52 +203,50 @@ Fonrey 是一套面向房产经纪公司的 B2B SaaS 平台,采用多租户架
|
||||
|
||||
**As** 忘记密码的经纪人,**I want** 通过手机号 + 短信验证码完成身份核验,重新设定密码,**So that** 无需邮箱、无需联系管理员,独立完成密码重置。
|
||||
|
||||
> **说明**:考虑到大多数Agent(经纪人)没有常用邮箱,本期找回密码统一通过短信验证码实现,废弃邮箱找回方式。账号中 `email` 字段在本系统无任何必须业务用途,完全可选。
|
||||
> **说明**:考虑到大多数经纪人没有常用邮箱,本期找回密码统一通过短信验证码实现,废弃邮箱找回方式。账号中邮箱字段在本系统无任何必须业务用途,完全可选。
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- [ ] 点击登录界面「忘记密码」链接,跳转至「找回密码」流程(Stepper 分步页面,共三步)
|
||||
- [ ] 点击登录页「忘记密码」链接,跳转至「找回密码」流程(分三步)
|
||||
|
||||
**步骤一:输入手机号**
|
||||
|
||||
- [ ] 页面显示:手机号输入框(11 位数字,自动过滤非数字)、「获取验证码」按钮、「返回登录」链接
|
||||
- [ ] 手机号为空或不足 11 位 → 点击「获取验证码」时在输入框下方提示「请输入完整的 11 位手机号」
|
||||
- [ ] 手机号为空或不足 11 位 → 点击「获取验证码」时输入框下方提示「请输入完整的 11 位手机号」
|
||||
- [ ] 手机号格式合法后,点击「获取验证码」,按钮进入 60 秒倒计时冷却态(「重新获取(59s)」),倒计时结束后按钮恢复可点击
|
||||
- [ ] 服务端收到请求后:
|
||||
- 若该手机号**存在**且账号状态为 `active`:向该号码发送 6 位数字短信验证码,有效期 **10 分钟**
|
||||
- 若手机号**不存在**或账号已停用:页面统一提示「如该手机号已注册,验证码将在 1 分钟内发送」(**不泄露账号是否存在**)
|
||||
- [ ] 同一手机号 1 小时内最多发送 **5 次**短信验证码,超限后提示「发送次数过多,请 1 小时后再试」
|
||||
- [ ] 不论该手机号是否注册,前端文案统一显示「如该手机号已注册,验证码将在 1 分钟内发送」(**不泄露账号是否存在**)
|
||||
- [ ] 后台仅在手机号存在且账号处于可用状态时实际发送短信
|
||||
- [ ] 同一手机号在一段时间窗口内发送次数有上限,超限后提示「发送次数过多,请稍后再试」
|
||||
- [ ] 短信内容模板:「【Fonrey 房睿】您的密码重置验证码为 {code},10 分钟内有效,请勿泄露。」
|
||||
|
||||
**步骤二:输入短信验证码**
|
||||
|
||||
- [ ] 页面显示:6 位验证码输入框(支持分格输入)、「重新发送」倒计时链接、「下一步」按钮
|
||||
- [ ] 「下一步」按钮:6 位验证码全部输入后方可点击
|
||||
- [ ] 服务端校验验证码:
|
||||
- 正确且未过期 → 进入步骤三,颁发一次性 `sms_reset_token`(有效期 15 分钟,一次性,服务端存储)
|
||||
- 错误 → 提示「验证码有误,请重新输入」,错误次数 ≥ 5 次则本次验证码作废,需重新获取
|
||||
- [ ] 校验结果:
|
||||
- 正确且未过期 → 进入步骤三
|
||||
- 错误 → 提示「验证码有误,请重新输入」;同一验证码连续错误达到上限后作废,需重新获取
|
||||
- 已过期 → 提示「验证码已过期,请重新获取」
|
||||
|
||||
**步骤三:重置密码**
|
||||
|
||||
- [ ] 步骤三依赖步骤二颁发的 `sms_reset_token`(通过 URL 参数或会话状态传递),Token 无效或过期 → 显示「操作已超时,请重新发起找回密码」,跳回步骤一
|
||||
- [ ] **本页面复用「设置新密码」公共组件**(与首次登录强制修改密码页面为同一组件,详见 §5.3.4),保持 UI 与交互逻辑完全一致;入口上下文不同时,仅页面标题和提示文案有所差异:
|
||||
- [ ] 步骤三依赖步骤二颁发的一次性凭证;凭证无效或过期 → 显示「操作已超时,请重新发起找回密码」,跳回步骤一
|
||||
- [ ] **本页面复用「设置新密码」公共组件**(与首次登录强制改密页为同一组件,详见 §6.4),保持 UI 与交互逻辑完全一致;入口上下文不同时,仅页面标题与提示文案差异:
|
||||
|
||||
| 元素 | 首次登录强制修改(§5.3.4) | 找回密码步骤三(本 Story) |
|
||||
| 元素 | 首次登录强制改密(§6.4) | 找回密码步骤三(本 Story) |
|
||||
|------|--------------------------|--------------------------|
|
||||
| 页面标题 | 「欢迎使用 Fonrey,请先设置您的登录密码」 | 「重置您的登录密码」 |
|
||||
| 提示文案 | 「您当前使用的是初始密码,为保障账号安全,请立即设置新密码后开始使用」 | 「请输入您的新密码,设置完成后请使用新密码重新登录」 |
|
||||
| 提交按钮文案 | 「确认并进入系统」 | 「确认重置密码」 |
|
||||
| 提交后跳转 | `is_initial_password = False`,Session 保持,直接进入首页 | 所有 Session 立即失效,跳转登录界面并提示「密码已重置,请使用新密码登录」 |
|
||||
| 提交后跳转 | Session 保持,直接进入首页 | 该账号所有 Session 立即失效,跳转登录页并提示「密码已重置,请使用新密码登录」 |
|
||||
|
||||
- [ ] 提交成功后:`is_initial_password` 置为 **`False`**(找回密码属于用户主动操作,已完成身份核验,无需再触发强制修改流程)
|
||||
> **注意**:与首次登录流程不同,找回密码时用户已通过短信验证码完成了身份核验,本次密码设置即视为"用户本人主动设置",不应再触发 `is_initial_password = True` 的二次强制修改。
|
||||
- [ ] 提交成功后:账号"初始密码"标记置为否(找回密码属于用户主动操作,已完成身份核验,**不应再触发首次登录强制改密流程**)
|
||||
|
||||
---
|
||||
|
||||
### Story 4:经纪人找回用户名(已废弃)
|
||||
|
||||
> **状态**:已废弃。普通员工用户名固定为手机号,无需找回;Tenant Admin 如忘记用户名,请联系平台运营线下处理。本 Story 保留占位以维持版本记录,实现时跳过此 Story。
|
||||
> **状态**:已废弃。普通员工用户名固定为手机号,无需找回;Tenant Admin 如忘记用户名请联系平台运营线下处理。本 Story 保留占位以维持版本记录,实现时跳过。
|
||||
|
||||
---
|
||||
|
||||
@@ -191,150 +254,103 @@ Fonrey 是一套面向房产经纪公司的 B2B SaaS 平台,采用多租户架
|
||||
|
||||
**As** 已有账号的经纪人,**I want** 通过手机号 + 短信验证码直接登录,**So that** 在忘记密码或不想输入密码时,仍能快速进入系统。
|
||||
|
||||
> **说明**:短信基础设施(`sms_otp_records` 表、OTP 发送/校验逻辑)已在 Story 3 找回密码中建设完成,本 Story 直接复用,实现成本极低。登录界面提供「密码登录」和「验证码登录」两个并列入口,用户自由切换,两种方式均为 MVP 正式功能。
|
||||
> **说明**:短信能力在 Story 3 找回密码中已建设完成,本 Story 复用。登录页提供「密码登录」和「验证码登录」两个并列 Tab,用户自由切换,两种方式均为 MVP 正式功能。
|
||||
|
||||
**验收标准**:
|
||||
|
||||
- [ ] 登录界面提供两种登录方式的切换 Tab:**「密码登录」**(默认选中)和 **「验证码登录」**
|
||||
- [ ] 登录页提供两种登录方式的切换 Tab:**「密码登录」**(默认选中)和 **「验证码登录」**
|
||||
- [ ] 切换 Tab 时,输入区域平滑切换,已填内容清空,滑块验证状态重置
|
||||
|
||||
**「验证码登录」界面元素**:
|
||||
- [ ] 手机号输入框(规格同 Story 2,11 位数字,自动过滤非数字)
|
||||
|
||||
- [ ] 手机号输入框(规格同 Story 2,11 位数字)
|
||||
- [ ] 验证码输入框(6 位数字分格输入)+ 「获取验证码」按钮(60 秒倒计时冷却态)
|
||||
- [ ] 滑块拼图验证区域(规格同 Story 2,**先通过滑块验证,再允许点击「获取验证码」**)
|
||||
- [ ] 「登录」按钮(手机号 + 验证码均填写后方可点击)
|
||||
|
||||
**获取验证码逻辑**:
|
||||
|
||||
- [ ] 用户须先完成滑块验证,「获取验证码」按钮方可点击;未完成滑块时点击 → 提示「请先完成滑块验证」
|
||||
- [ ] 点击「获取验证码」后,服务端:
|
||||
- 手机号格式不合法 → 前端拦截,提示「请输入完整的 11 位手机号」
|
||||
- 手机号存在且状态 `active` → 发送 6 位 OTP,有效期 **5 分钟**,存入 `sms_otp_records`(`scene = 'login'`)
|
||||
- 手机号不存在或已停用 → 统一响应「如该手机号已注册,验证码将在 1 分钟内发送」(防止枚举攻击)
|
||||
- [ ] 同一手机号 1 小时内最多发送 **10 次**登录验证码(找回密码为独立计数,两者不共享限额);超限后提示「发送次数过多,请 1 小时后再试」
|
||||
- [ ] 手机号格式不合法 → 前端拦截,提示「请输入完整的 11 位手机号」
|
||||
- [ ] 不论手机号是否注册,前端文案统一显示「如该手机号已注册,验证码将在 1 分钟内发送」(防止枚举攻击)
|
||||
- [ ] 后台仅在手机号存在且账号处于可用状态时实际发送短信
|
||||
- [ ] 同一手机号在一段时间窗口内的发送次数有上限(与找回密码独立计数,互不共享);超限后提示「发送次数过多,请稍后再试」
|
||||
- [ ] 短信内容模板:「【Fonrey 房睿】您的登录验证码为 {code},5 分钟内有效,请勿泄露。」
|
||||
|
||||
**登录校验逻辑**:
|
||||
- [ ] 点击「登录」,服务端校验 OTP:
|
||||
- 正确且未过期 → 登录成功,后续行为与 Story 2 密码登录完全一致(含 `is_initial_password` 判断)
|
||||
- 错误 → 提示「验证码有误,请重新输入」;连续错误 ≥ 5 次 → 本次 OTP 作废,提示「验证码已失效,请重新获取」
|
||||
|
||||
- [ ] 校验结果:
|
||||
- 正确且未过期 → 登录成功,后续行为与 Story 2 密码登录完全一致(含初始密码状态判断)
|
||||
- 错误 → 提示「验证码有误,请重新输入」;连续错误达到上限 → 本次验证码作废,提示「验证码已失效,请重新获取」
|
||||
- 已过期 → 提示「验证码已过期,请重新获取」
|
||||
- [ ] **账号被锁定**(密码登录失败次数触发):验证码登录仍受账号锁定限制,锁定期间无法通过任何方式登录,提示「账号已被临时锁定,请 30 分钟后重试,或联系管理员解锁」
|
||||
- [ ] **账号被锁定**(密码登录失败次数触发):验证码登录仍受账号锁定限制,锁定期间无法通过任何方式登录,提示与 Story 2 一致
|
||||
> **设计说明**:账号锁定是账号维度的安全策略,不区分登录方式;否则锁定形同虚设。
|
||||
- [ ] **账号已停用**:提示「账号已停用,请联系您的管理员」
|
||||
|
||||
**接口规范**:
|
||||
---
|
||||
|
||||
```
|
||||
POST /api/auth/login/phone/
|
||||
Request: { phone: string, sms_code: string }
|
||||
Response: { token: string, is_initial_password: bool, user: {...} } | { error_code: string, message: string }
|
||||
```
|
||||
### Story 6:预留——微信扫码登录(v2 实现)
|
||||
|
||||
**As** 绑定了微信账号的经纪人,**I want** 在登录页扫描微信二维码完成登录,**So that** 免去输入账号密码的步骤,提升登录体验。
|
||||
|
||||
**当前状态**:
|
||||
|
||||
- 本期登录页 UI 入口以「即将开放」禁用态展示,**不提供任何可点击的实际功能**
|
||||
- 后端服务端在 MVP 中**不开放微信相关接口**,相关端点仅占位规划,详见 Tech 文档 §5.4
|
||||
- v2 实现时的业务前置要求:
|
||||
- 微信账号必须先在「个人设置」中与系统账号完成绑定
|
||||
- 二维码有效期 3 分钟,过期后前端自动刷新二维码
|
||||
- 同一微信账号在同一租户内只能绑定一个系统账号
|
||||
|
||||
---
|
||||
|
||||
### Story 6:预留——微信扫码登录(接口预留,v2 实现)
|
||||
## 6. 业务规则与功能详细说明
|
||||
|
||||
**As** 绑定了微信账号的经纪人,**I want** 在登录界面扫描微信二维码完成登录,**So that** 免去输入账号密码的步骤,提升登录体验。
|
||||
|
||||
**当前状态**:本期 UI 入口以「即将开放」禁用态展示于登录界面,接口定义预留,不开放实际功能。
|
||||
|
||||
**预留接口设计**(供后端提前规划):
|
||||
|
||||
```
|
||||
GET /api/auth/wechat/qrcode/ # 获取微信扫码二维码(含 state + 有效期)
|
||||
POST /api/auth/wechat/callback/ # 微信扫码确认后回调,换取系统 Token
|
||||
```
|
||||
|
||||
**绑定条件**(v2 实现时的前置要求):
|
||||
- 微信账号必须先在「个人设置」中与用户名账号完成绑定
|
||||
- 二维码有效期 3 分钟,过期后前端自动刷新二维码
|
||||
- 微信账号只能绑定一个用户名账号(同一租户内)
|
||||
|
||||
---
|
||||
|
||||
## 5. 功能详细说明
|
||||
|
||||
### 5.1 客户端 Tenant 识别流程
|
||||
|
||||
#### 5.1.1 流程概述
|
||||
### 6.1 客户端 Tenant 识别业务流程
|
||||
|
||||
```
|
||||
客户端启动
|
||||
│
|
||||
├─ 本地有 Tenant Code 缓存?
|
||||
│ │
|
||||
│ YES ──→ 校验缓存 Tenant Code 是否仍有效(服务端 validate)
|
||||
│ YES ──→ 复核缓存 Tenant Code 是否仍有效
|
||||
│ │
|
||||
│ 有效 ──→ 直接进入登录界面
|
||||
│ 有效 ──→ 直接进入登录页
|
||||
│ │
|
||||
│ 无效 ──→ 清除缓存,进入 Tenant 识别界面
|
||||
│ 无效 ──→ 清除缓存,进入 Tenant 识别页
|
||||
│
|
||||
└─ NO ──→ 显示 Tenant 识别界面
|
||||
└─ NO ──→ 显示 Tenant 识别页
|
||||
│
|
||||
用户输入 Tenant Code → 发起验证
|
||||
│
|
||||
验证成功 ──→ 缓存 Tenant Code → 进入登录界面
|
||||
验证成功 ──→ 缓存 Tenant Code → 进入登录页
|
||||
│
|
||||
验证失败 ──→ 显示错误信息,保持识别界面
|
||||
验证失败 ──→ 显示错误信息,保持识别页
|
||||
```
|
||||
|
||||
#### 5.1.2 Tenant 识别界面规范
|
||||
#### Tenant 识别页规范
|
||||
|
||||
| 元素 | 规格 |
|
||||
| ------------- | --------------------------------------- |
|
||||
| 页面背景 | 品牌色渐变(与登录界面保持一致的视觉风格) |
|
||||
| Logo | Fonrey 产品 Logo,居中显示 |
|
||||
| 标题 | 「欢迎使用 Fonrey 房睿」 |
|
||||
| 副标题 | 「请输入您公司的专属识别码以继续」 |
|
||||
| 元素 | 规格 |
|
||||
| ----------- | --------------------------------------- |
|
||||
| 页面背景 | 品牌色渐变(与登录页保持一致的视觉风格) |
|
||||
| Logo | Fonrey 产品 Logo,居中显示 |
|
||||
| 标题 | 「欢迎使用 Fonrey 房睿」 |
|
||||
| 副标题 | 「请输入您公司的专属识别码以继续」 |
|
||||
| Tenant Code 输入框 | 单行数字输入,固定 12 位,支持粘贴;非数字字符自动过滤,超出 12 位截断 |
|
||||
| 输入框 Label | 「公司识别码(Tenant Code)」 |
|
||||
| 确认按钮 | 主色调按钮,文字「确认」 |
|
||||
| 错误提示 | 输入框下方红色文字,固定区域占位(不影响布局抖动) |
|
||||
| 帮助文案 | 「不知道识别码?请联系您公司的Tenant Admin(租户管理员)」 |
|
||||
| 输入框 Label | 「公司识别码(Tenant Code)」 |
|
||||
| 确认按钮 | 主色调按钮,文字「确认」 |
|
||||
| 错误提示 | 输入框下方红色文字,固定区域占位(不影响布局抖动) |
|
||||
| 帮助文案 | 「不知道识别码?请联系您公司的Tenant Admin(租户管理员)」 |
|
||||
|
||||
#### 5.1.3 Tenant Code 格式规范
|
||||
|
||||
- **格式**:固定 **12 位纯数字**,如 `202500010001`
|
||||
- **生成规则**(建议):由平台运营在系统管理后台开通租户时自动生成,不允许手动指定,确保全局唯一性;可采用时间戳前缀 + 随机后缀的方式生成(如 `YYYYMM` + 6 位随机数)
|
||||
- **前端校验**:输入框仅接受数字字符(非数字自动过滤),输入满 12 位后自动触发格式完成状态;少于 12 位时点击「确认」弹出提示「识别码须为 12 位数字」
|
||||
- **唯一性**:全局唯一(公共 Schema 层面),同一 Tenant Code 不可分配给多个租户
|
||||
- **客户端存储**:Electron `app.getPath('userData')` 目录下的配置文件(加密存储,防止明文读取)
|
||||
|
||||
#### 5.1.4 服务端 Tenant 验证接口规范
|
||||
|
||||
```
|
||||
POST /api/auth/tenant/verify/
|
||||
|
||||
Request Body:
|
||||
{
|
||||
"tenant_code": "202500010001"
|
||||
}
|
||||
|
||||
Response 200 (成功):
|
||||
{
|
||||
"valid": true,
|
||||
"tenant_name": "XX房产经纪有限公司",
|
||||
"tenant_logo_url": "https://cdn.fonrey.com/tenants/xxx/logo.png",
|
||||
"login_url": "https://xxx.fonrey.com/auth/login/"
|
||||
}
|
||||
|
||||
Response 200 (失败):
|
||||
{
|
||||
"valid": false,
|
||||
"error_code": "TENANT_NOT_FOUND",
|
||||
"message": "识别码无效"
|
||||
}
|
||||
```
|
||||
|
||||
> **注意**:该接口属于 `shared_apps` 范围,路由在公共 Schema 下,不需要租户鉴权,但需要限流保护(每 IP 每分钟 ≤ 10 次请求)。
|
||||
> Tenant 验证接口的具体路径、请求/响应 Schema、限流阈值与 Schema 隔离实现:见 `TECH_STACK/登录管理技术方案.md` §5.3.1 与 §三。
|
||||
|
||||
---
|
||||
|
||||
### 5.2 登录界面设计规范
|
||||
### 6.2 登录页设计规范
|
||||
|
||||
#### 5.2.1 界面布局
|
||||
#### 6.2.1 页面布局
|
||||
|
||||
登录界面顶部以 **Tab 切换**区分两种登录方式(「密码登录」默认选中),Tab 下方的表单区随当前选中 Tab 动态切换,微信扫码作为独立的「其他登录」保持禁用。
|
||||
登录页顶部以 **Tab 切换** 区分两种登录方式(「密码登录」默认选中),Tab 下方的表单区随当前选中 Tab 动态切换;微信扫码作为独立的「其他登录」保持禁用。
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
@@ -382,80 +398,83 @@ Response 200 (失败):
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 5.2.2 安全机制
|
||||
#### 6.2.2 安全机制(业务视角)
|
||||
|
||||
| 机制 | 规格 |
|
||||
| 机制 | 业务规则 |
|
||||
|------|------|
|
||||
| 验证码类型 | **滑块拼图行为验证码**:展示带缺口的背景图 + 可拖动的拼图碎片,用户滑动碎片至缺口完成验证,无需输入字符 |
|
||||
| 验证逻辑 | 服务端综合校验**位置偏差**(缺口中心 ±5px 容差)+ **滑动轨迹特征**(加速/减速曲线、总耗时),双重判断是否为人类行为 |
|
||||
| 背景图来源 | 预置图库随机抽取,缺口位置每次服务端随机生成,防止固定模式被预测 |
|
||||
| 验证码有效期 | 单次验证会话有效,提交登录后服务端 Token 立即失效;超过 3 分钟未操作需重新加载 |
|
||||
| 验证失败处理 | 拼图区域抖动动画提示,自动刷新新背景图;**不计入账号密码错误次数**(行为验证失败属独立事件) |
|
||||
| 密码错误锁定 | 同一账号连续密码错误 ≥ 5 次,锁定 30 分钟;解锁方式:等待超时自动解锁 或 管理员手动解锁 |
|
||||
| 密码错误计数 | 计数存于 Redis,Key 格式:`login_fail:tenant_id:phone`(phone 即用户名/手机号),TTL 30 分钟 |
|
||||
| 验证码刷新 | 登录失败(用户名/密码错误)后自动刷新拼图;用户亦可主动点击「刷新」图标重新加载背景图 |
|
||||
| HTTPS | 所有登录相关请求强制 HTTPS,不允许 HTTP 降级 |
|
||||
| 密码传输 | 前端不做密码加密,HTTPS 层保证传输安全;后端存储使用 `django.contrib.auth` 默认的 `PBKDF2+SHA256` 哈希 |
|
||||
| Session 有效期 | 默认 8 小时(工作日单日使用场景);可由租户管理员在「系统设置」中调整 |
|
||||
| 验证码类型 | 滑块拼图行为验证码:用户拖动碎片至缺口完成验证,无需输入字符 |
|
||||
| 验证判定 | 综合位置精度与滑动轨迹特征判断是否为人类行为;具体容差与算法见 Tech 文档 |
|
||||
| 背景图来源 | 预置图库随机抽取,缺口位置每次随机生成,防止固定模式被预测 |
|
||||
| 验证失败处理 | 拼图区域抖动提示,自动刷新新背景图;**不计入账号密码错误次数** |
|
||||
| 密码错误锁定 | 同一账号连续密码错误达到阈值后自动锁定,到期自动解锁;管理员可手动解锁 |
|
||||
| 验证码刷新 | 登录失败后自动刷新拼图;用户亦可主动点击「刷新」图标 |
|
||||
| 传输安全 | 所有登录相关请求强制 HTTPS,不允许 HTTP 降级 |
|
||||
| 会话有效期 | 默认按工作日单日使用场景设定;可由 Tenant Admin 在「系统设置」中调整 |
|
||||
|
||||
> 滑块容差像素值、密码错误次数阈值、锁定时长、Session 默认时长、密码哈希算法、登录失败计数存储位置等实现口径,统一由 `TECH_STACK/登录管理技术方案.md` §六、§七、§八 定义;本 PRD 不重复。
|
||||
|
||||
---
|
||||
|
||||
### 5.3 账号与员工实名绑定规范
|
||||
### 6.3 账号与员工实名绑定规范
|
||||
|
||||
#### 5.3.1 绑定原则
|
||||
#### 6.3.1 绑定原则
|
||||
|
||||
- 每个系统登录账号必须与「组织人事管理」模块中的一条**员工档案(Staff)**绑定
|
||||
- 账号与员工是 **1:1 关系**,一个员工对应一个账号,一个账号只能绑定一个员工
|
||||
- **不支持用户自行注册**,所有账号均由有权限的管理角色创建
|
||||
|
||||
#### 5.3.2 账号创建权限分层
|
||||
#### 6.3.2 账号创建权限分层
|
||||
|
||||
系统内共有两类账号创建场景,权限和规则各不相同:
|
||||
|
||||
**② Tenant Admin 账号(每个租户的超级管理账号)**
|
||||
**① Tenant Admin 账号(每个租户的超级管理账号)**
|
||||
|
||||
| 项目 | 规格 |
|
||||
| 项目 | 业务规则 |
|
||||
| ---- | ------------------------------------------------------------ |
|
||||
| 创建时机 | 平台运营在系统管理后台开通租户时,系统**自动**以该租户联系人手机号创建 Tenant Admin 账号,无需手动设置 |
|
||||
| 用户名 | **固定为该租户联系人的手机号**(11 位数字),全局唯一,创建后不可更改 |
|
||||
| 初始密码 | **系统统一固定初始密码**(与普通员工相同,由平台在部署配置中设定,如 `Fonrey@2025`) |
|
||||
| 首次登录 | 强制修改初始密码,不可跳过 |
|
||||
| 权限范围 | 拥有该租户内最高权限,可管理员工账号、角色、系统设置等 |
|
||||
| 数量限制 | 每个租户仅限 1 个 Tenant Admin 账号(后续可扩展为多管理员,v2 规划) |
|
||||
| 数据来源 | 联系人手机号来自 `public.tenants.contact_phone` 字段,开通租户时由平台运营录入,必填 |
|
||||
| 创建时机 | 平台运营在平台管理后台开通租户时,系统**自动**以该租户联系人手机号创建 Tenant Admin 账号,无需手动设置 |
|
||||
| 用户名 | **固定为该租户联系人的手机号**(11 位数字),全局唯一,创建后不可更改 |
|
||||
| 初始密码 | 系统统一固定初始密码(由平台运营在系统配置中设定),与普通员工相同 |
|
||||
| 首次登录 | 强制修改初始密码,不可跳过 |
|
||||
| 权限范围 | 拥有该租户内最高权限,可管理员工账号、角色、系统设置等 |
|
||||
| 数量限制 | 每个租户仅限 1 个 Tenant Admin 账号(v2 可扩展为多管理员) |
|
||||
| 数据来源 | 联系人手机号在开通租户时由平台运营录入,必填 |
|
||||
|
||||
**① 普通员工账号(经纪人、店长、行政等)**
|
||||
**② 普通员工账号(经纪人、店长、行政等)**
|
||||
|
||||
| 项目 | 规格 |
|
||||
| 项目 | 业务规则 |
|
||||
|------|------|
|
||||
| 创建时机 | Tenant Admin 在「组织人事管理 → 新增员工」时,系统自动为该员工创建登录账号 |
|
||||
| 用户名 | **固定为该员工的手机号**(11 位数字),同租户内唯一,创建后不可更改 |
|
||||
| 初始密码 | **系统统一固定初始密码**(由平台在部署配置中设定,如 `Fonrey@2025`),所有新员工账号均使用同一初始密码 |
|
||||
| 首次登录 | 强制修改初始密码,**不可跳过**(详见 5.3.4) |
|
||||
| 密码重置 | Tenant Admin 可在员工管理界面对任意员工账号执行「重置密码」,重置后恢复为固定初始密码,触发首次登录强制修改流程 |
|
||||
| 初始密码 | 系统统一固定初始密码(与 Tenant Admin 共用同一配置) |
|
||||
| 首次登录 | 强制修改初始密码,**不可跳过**(详见 §6.4) |
|
||||
| 密码重置 | Tenant Admin 可在员工管理界面对任意员工账号执行「重置密码」,重置后恢复为固定初始密码,触发首次登录强制改密流程 |
|
||||
| 账号禁用 | 员工离职或被停用时,对应账号自动禁用;禁用账号无法登录,历史操作记录保留 |
|
||||
|
||||
#### 5.3.3 账号字段规范
|
||||
#### 6.3.3 账号字段语义(业务视角)
|
||||
|
||||
| 字段 | 类型 | Tenant Admin | 普通员工账号 | 说明 |
|
||||
|------|------|-------------|-------------|------|
|
||||
| 用户名(username) | CharField(30) | **固定为联系人手机号**(11 位数字) | **固定为员工手机号**(11 位数字) | 登录 ID,创建后不可更改;两类账号规则统一 |
|
||||
| 密码(password) | CharField | **系统统一固定初始密码** | **系统统一固定初始密码** | PBKDF2+SHA256 哈希存储;首次登录强制修改 |
|
||||
| 手机号(phone) | CharField(11) | **必填,同时作为用户名**,来源于 `public.tenants.contact_phone` | **必填,同时作为用户名**,加密存储,同租户内唯一 | 两类账号均用手机号登录,v2 启用手机验证码后复用此字段 |
|
||||
| 邮箱(email) | EmailField | 选填,同租户唯一 | 选填,同租户唯一 | 在本系统无必须业务用途,完全可选;普通员工忘记密码通过手机短信验证码自助找回,**与邮箱无关** |
|
||||
| 员工档案关联(staff_id) | OneToOneField → `org.Staff` | 可选关联(平台运营账号) | 必须关联 | 实名绑定 |
|
||||
| 账号状态(status) | CharField | `active` / `disabled` / `locked` | `active` / `disabled` / `locked` | locked 为密码错误锁定,30 分钟自动恢复 |
|
||||
| 初始密码标记(is_initial_password) | BooleanField | True(首次登录前) | True(首次登录前) | True 时登录成功后强制跳转修改密码页 |
|
||||
| 创建人(created_by) | ForeignKey → self | 平台运营(系统管理后台) | Tenant Admin | 审计追溯 |
|
||||
| 字段 | Tenant Admin | 普通员工 | 业务说明 |
|
||||
|------|------|------|------|
|
||||
| 用户名 | 联系人手机号 | 员工手机号 | 登录 ID,创建后不可更改 |
|
||||
| 密码 | 系统统一初始密码 | 系统统一初始密码 | 必须安全哈希存储;首次登录强制修改 |
|
||||
| 手机号 | 必填,同时作为用户名 | 必填,同时作为用户名 | 用于密码登录与短信验证码登录;存储须加密 |
|
||||
| 邮箱 | 选填 | 选填 | 在本系统无必须业务用途,完全可选 |
|
||||
| 员工档案关联 | 可选关联 | 必须关联 | 实名绑定 |
|
||||
| 账号状态 | active / disabled / locked | active / disabled / locked | locked 为密码错误锁定,到期自动恢复 |
|
||||
| 初始密码标记 | 是 / 否 | 是 / 否 | 为"是"时登录成功后强制跳转改密页 |
|
||||
| 创建人 | 平台运营 | Tenant Admin | 审计追溯 |
|
||||
|
||||
#### 5.3.4 首次登录强制修改密码
|
||||
> 字段类型、字段名、表名、索引、跨 App 依赖、Migration 顺序等实现口径,全部以 `DATA_MODEL/DATA_MODEL_LOGIN.md` 为唯一权威。
|
||||
|
||||
- 新员工账号创建后,`is_initial_password = True`,账号处于「初始密码」状态
|
||||
- 员工使用手机号(用户名)+ 固定初始密码登录成功后,系统**立即跳转**至「修改初始密码」强制页面,**不可关闭、不可跳过**,任何其他系统功能页面均不可访问
|
||||
- Tenant Admin 对员工账号执行「重置密码」后,`is_initial_password` 重置为 True,该员工下次登录时再次触发强制修改流程
|
||||
- 修改成功后,`is_initial_password` 更新为 False,原 Session 保持有效,直接进入系统首页
|
||||
---
|
||||
|
||||
**强制修改密码页面规范**:
|
||||
### 6.4 首次登录强制修改密码
|
||||
|
||||
- 新员工账号创建后,账号处于「初始密码」状态
|
||||
- 员工使用手机号 + 固定初始密码登录成功后,系统**立即跳转**至「首次登录强制改密页」,**不可关闭、不可跳过**,任何其他系统功能页面均不可访问
|
||||
- Tenant Admin 对员工账号执行「重置密码」后,账号重新进入「初始密码」状态,该员工下次登录时再次触发强制改密流程
|
||||
- 修改成功后,账号脱离「初始密码」状态,原 Session 保持有效,直接进入系统首页
|
||||
|
||||
**首次登录强制改密页规范**:
|
||||
|
||||
| 元素 | 规格 |
|
||||
|------|------|
|
||||
@@ -467,13 +486,13 @@ Response 200 (失败):
|
||||
| 提交按钮 | 「确认并进入系统」 |
|
||||
| 不可操作项 | 无「跳过」按钮;顶部导航栏、侧边菜单、关闭按钮均禁用 |
|
||||
|
||||
> 历史密码校验范围、密码强度算法等实现细节见 Tech 文档与 `DATA_MODEL_LOGIN.md` 中历史密码记录表设计。
|
||||
|
||||
---
|
||||
|
||||
### 5.4 找回密码详细说明
|
||||
### 6.5 找回密码业务流程
|
||||
|
||||
> **说明**:Story 4「找回用户名」已废弃。普通员工用户名固定为手机号,无需找回;Tenant Admin 如忘记用户名请联系平台运营线下处理。
|
||||
|
||||
#### 5.4.1 找回密码流程
|
||||
> 实现细节(一次性凭证 TTL、OTP 有效期、错误次数阈值、限流计数策略)见 `TECH_STACK/登录管理技术方案.md` §6.3 与 §七。
|
||||
|
||||
```
|
||||
用户点击「忘记密码」
|
||||
@@ -482,143 +501,127 @@ Response 200 (失败):
|
||||
│
|
||||
├─ 输入 11 位手机号,点击「获取验证码」
|
||||
│ │
|
||||
│ 服务端校验手机号是否存在且状态为 active
|
||||
│ 前端文案统一为「如该手机号已注册,验证码将在 1 分钟内发送」(防止枚举)
|
||||
│ │
|
||||
│ 统一响应「如该手机号已注册,验证码将在 1 分钟内发送」(防止枚举)
|
||||
│ │
|
||||
│ 后台:存在且 active → 生成 6 位 OTP,有效期 10 分钟,存入 sms_otp_records → 发送短信
|
||||
│ 后台:手机号存在且账号可用 → 生成 OTP → 发送短信
|
||||
│ 不存在或已停用 → 静默处理
|
||||
│
|
||||
步骤2:输入短信验证码
|
||||
│
|
||||
├─ 输入 6 位验证码,点击「下一步」
|
||||
│ │
|
||||
│ 服务端校验 OTP:
|
||||
│ │
|
||||
│ 正确且未过期 → 颁发一次性 sms_reset_token(有效期 15 分钟)→ 进入步骤3
|
||||
│ │
|
||||
│ 错误(累计 < 5 次)→ 提示「验证码有误,请重新输入」
|
||||
│ 错误(累计 ≥ 5 次)→ 提示「验证已失败,请重新获取验证码」,本次 OTP 作废
|
||||
│ 正确且未过期 → 颁发一次性凭证 → 进入步骤3
|
||||
│ 错误(次数未到上限)→ 提示「验证码有误,请重新输入」
|
||||
│ 错误(达到上限)→ 提示「验证已失败,请重新获取验证码」,本次 OTP 作废
|
||||
│ 已过期 → 提示「验证码已过期,请重新获取」
|
||||
│
|
||||
步骤3:重置密码
|
||||
│
|
||||
├─ 页面携带 sms_reset_token,服务端校验有效性
|
||||
├─ 服务端校验一次性凭证有效性
|
||||
│ │
|
||||
│ 无效/过期 → 提示「操作已超时,请重新发起找回密码」,跳回步骤1
|
||||
│ │
|
||||
│
|
||||
├─ 用户输入新密码 + 确认新密码,实时逐条校验复杂度规则(✓/✗)
|
||||
│
|
||||
└─ 提交成功
|
||||
→ 更新密码,is_initial_password = False
|
||||
→ 更新密码,账号脱离「初始密码」状态
|
||||
→ 清除该账号所有有效 Session(强制重新登录)
|
||||
→ 跳转登录界面,提示「密码已重置,请使用新密码登录」
|
||||
→ 跳转登录页,提示「密码已重置,请使用新密码登录」
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.5 手机验证码登录详细说明
|
||||
### 6.6 手机验证码登录(业务规则补充)
|
||||
|
||||
> 本节为 Story 5 的实现规范补充。短信基础设施(`sms_otp_records` 表、OTP 发送/校验逻辑)在 Story 3 找回密码中已建设完成,本节描述在**登录场景**下复用该基础设施时的关键差异点。
|
||||
> 本节为 Story 5 的业务规则补充。短信能力在 Story 3 找回密码中已建设完成,本节描述在**登录场景**下复用时的关键业务差异点。
|
||||
|
||||
**与找回密码短信逻辑的差异对比**:
|
||||
**与找回密码短信逻辑的业务差异对比**:
|
||||
|
||||
| 维度 | 找回密码(Story 3) | 验证码登录(Story 5) |
|
||||
|------|-------------------|---------------------|
|
||||
| `scene` 字段 | `password_reset` | `login` |
|
||||
| OTP 有效期 | 10 分钟 | 5 分钟 |
|
||||
| 每小时发送上限 | 5 次 | 10 次 |
|
||||
| 验证成功后动作 | 颁发 `sms_reset_token` → 步骤三重置密码 | 直接颁发 Session Token,登录成功 |
|
||||
| 业务场景 | 密码重置 | 登录认证 |
|
||||
| OTP 有效期 | 较长 | 较短 |
|
||||
| 每小时发送上限 | 较低 | 较高 |
|
||||
| 验证成功后动作 | 颁发一次性凭证 → 步骤三重置密码 | 直接登录成功 |
|
||||
| 短信文案 | 「密码重置验证码」 | 「登录验证码」 |
|
||||
| 账号锁定影响 | 不受密码错误锁定限制(非密码登录路径) | **受账号锁定限制**(账号维度安全策略,不区分方式)|
|
||||
|
||||
> 各项数值(OTP 时长、每小时上限)口径见 `TECH_STACK/登录管理技术方案.md` §6.3、§6.4、§七。
|
||||
|
||||
**滑块验证前置规则**(验证码登录特有):
|
||||
|
||||
- 用户须先完成滑块拼图验证,「获取验证码」按钮方可点击
|
||||
- 滑块验证通过后,拼图区域保持「验证通过」状态,不需要在点击「登录」前再次验证
|
||||
- 切换 Tab 时,滑块验证状态重置(须重新完成验证后方可获取验证码)
|
||||
|
||||
**`sms_otp_records` 表复用说明**:
|
||||
**短信记录复用说明**:
|
||||
|
||||
- 不新建表,复用 `DATA_MODEL_LOGIN.md` 中定义的 `sms_otp_records`
|
||||
- `scene` 字段区分场景:`login` / `password_reset`,各自独立限流计数
|
||||
- 同一手机号同一 scene 同一时间只有一条有效 OTP;新发送时将旧记录标记为 `used`
|
||||
- 不新建表,复用 `DATA_MODEL_LOGIN.md` 中定义的短信验证码记录表
|
||||
- 通过场景字段区分"登录"与"密码重置",各自独立限流计数
|
||||
- 同一手机号同一场景同一时间只有一条有效 OTP;新发送时将旧记录置为失效
|
||||
|
||||
---
|
||||
|
||||
### 5.6 后端数据模型设计
|
||||
### 6.7 后端数据模型
|
||||
|
||||
> **数据模型已迁移至独立文档**,请参阅:
|
||||
> **`Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN.md`**
|
||||
> 数据模型已迁移至独立文档,请参阅:**`DATA_MODEL/DATA_MODEL_LOGIN.md`**
|
||||
|
||||
该文档包含:
|
||||
- `user_accounts` 账号主表(完整字段定义、约束、索引、Django Model 代码)
|
||||
- `login_attempts` 登录审计表
|
||||
- `sms_otp_records` 短信验证码记录表(找回密码 + 验证码登录共用)
|
||||
- `password_histories` 历史密码记录表
|
||||
|
||||
- 账号主表(完整字段定义、约束、索引)
|
||||
- 登录审计表
|
||||
- 短信验证码记录表(找回密码 + 验证码登录共用)
|
||||
- 历史密码记录表
|
||||
- Redis 缓存结构说明
|
||||
- 账号状态机与创建流程
|
||||
- 与 `org.Staff` 的关联规则及跨 App 依赖设计
|
||||
- Django Migrations 迁移顺序说明
|
||||
- Migrations 迁移顺序说明
|
||||
- 架构决策说明(ADR)
|
||||
|
||||
---
|
||||
|
||||
### 5.7 Electron 客户端登录相关约定
|
||||
### 6.8 Electron 客户端约定
|
||||
|
||||
| 约定项 | 规格 |
|
||||
|--------|------|
|
||||
| Tenant Code 存储 | `electron-store` 或 `app.getPath('userData')` + AES 加密,不存储明文 |
|
||||
| Session Token 存储 | 内存(`global` 变量)+ `session` Cookie(Chromium 管理),不写入磁盘明文文件 |
|
||||
| 登录页加载 | 客户端主进程根据 Tenant Code 构建目标 URL(`https://{tenant_slug}.fonrey.com/auth/login/`),通过 `BrowserWindow.loadURL()` 加载 |
|
||||
| 多标签页处理 | 同一 `BrowserWindow` 内,所有页面共享同一 Session Cookie |
|
||||
| 客户端登出 | 调用服务端 `POST /api/auth/logout/` 使服务端 Session 失效 + 清除 Chromium Session Cookie |
|
||||
| 窗口关闭时 | Session 保留(不自动登出),下次打开客户端时若 Session 未过期,直接进入系统 |
|
||||
| 强制更新场景 | 若客户端版本低于服务端 `min_required_version`,则在登录界面前先展示「请更新客户端」提示,阻断登录流程(参见发布管理模块 PRD)|
|
||||
> Electron 客户端在登录链路上的实现约定(Tenant Code 加密存储、Session Cookie 策略、登录页加载、多标签页、登出、窗口关闭、强制更新、安全约束)已迁移至 `TECH_STACK/登录管理技术方案.md` §十三 Electron 客户端约定。
|
||||
|
||||
本 PRD 仅约束业务行为:
|
||||
|
||||
- 客户端必须在登录前完成 Tenant 识别,且 Tenant Code 须**加密**持久化
|
||||
- 客户端登出后,本地不得保留可直接复用的登录凭证
|
||||
- 客户端版本低于服务端要求的最低版本时,**必须阻断登录流程**并展示更新提示(联动平台管理后台 PRD 的客户端发布章节)
|
||||
- 同一客户端窗口内的多标签页应共享同一登录态
|
||||
|
||||
---
|
||||
|
||||
## 6. 技术注意事项
|
||||
## 7. 技术注意事项(产品视角)
|
||||
|
||||
### 6.1 依赖与技术选型
|
||||
### 7.1 业务依赖
|
||||
|
||||
| 依赖项 | 用途 | 说明 |
|
||||
|--------|------|------|
|
||||
| `django.contrib.auth` | 用户认证基础框架 | 扩展 `AbstractBaseUser` 而非直接使用 `User` 模型,以支持 `username` 唯一性约束在租户维度而非全局 |
|
||||
| `django-tenants` | 多租户隔离 | `UserAccount` 属于租户级 Schema,Tenant 验证接口属于 `shared_apps` |
|
||||
| `Redis` | 滑块验证 Token 存储、登录失败计数、短信 OTP 限流计数 | 验证 Key:`captcha_token:{uuid}`(TTL 3min);登录失败 Key:`login_fail:{tenant_id}:{username}`;OTP 限流 Key:`sms_limit:{scene}:{phone}`(TTL 1h)|
|
||||
| 短信服务(待选型) | 发送登录验证码 / 找回密码验证码 | 国内需选用具备短信资质的服务商(如阿里云短信、腾讯云短信);需申请短信签名和模板审核 |
|
||||
| `Celery` | 异步任务处理 | 短信发送异步处理,防止接口响应超时;原邮件发送需求已废弃,短信为主要通知方式 |
|
||||
| `django-ratelimit` 或自定义中间件 | 接口限流 | Tenant 验证接口、登录接口、找回密码接口均需限流 |
|
||||
| `Pillow` | 滑块拼图图片处理 | 生成拼图背景图(抠出缺口区域)及对应的拼图碎片图片,输出为 Base64,分别通过两个字段返回给前端 |
|
||||
- 短信发送依赖具备短信资质的服务商;签名与模板审核须在功能上线前完成
|
||||
- 短信发送须异步处理,避免阻塞登录链路;密码登录可作为短信故障时的保底入口
|
||||
- 多租户隔离与跨 Schema 调用细节由 `TECH_STACK/登录管理技术方案.md` 与 `DATA_MODEL/DATA_MODEL_LOGIN.md` 定义
|
||||
|
||||
### 6.2 多租户下的 `UserAccount` 隔离
|
||||
|
||||
- `UserAccount` 表位于**租户 Schema 内**(`django-tenants` 租户隔离范围),因此 username 唯一性约束在租户维度生效,不同租户的经纪人可以有相同用户名
|
||||
- Tenant 验证接口(`/api/auth/tenant/verify/`)位于**公共 Schema**(`shared_apps`),使用 `TenantModel` 查询
|
||||
- 登录、找回密码等接口通过请求域名(`{tenant_slug}.fonrey.com`)切换到对应租户 Schema(`django-tenants` 中间件自动处理)
|
||||
|
||||
### 6.3 已知风险
|
||||
### 7.2 已知风险
|
||||
|
||||
| 风险 | 可能性 | 影响 | 缓解措施 |
|
||||
|------|--------|------|---------|
|
||||
| 滑块验证被机器模拟轨迹绕过 | 低 | 高 | 服务端同时校验位置偏差 + 轨迹曲线特征(非线性运动特征),拒绝匀速/程序化轨迹;后续可引入设备指纹加固 |
|
||||
| Tenant Code 枚举攻击(暴力试探) | 低 | 中 | Tenant 验证接口限流(每IP每分钟≤10次),返回结果不区分「未找到」与「已禁用」|
|
||||
| 密码重置 Token 泄露 | 低 | 高 | `sms_reset_token` 单次有效、15 分钟过期、HTTPS 传输 |
|
||||
| 短信服务故障导致用户无法找回密码或验证码登录 | 中 | 高 | 短信发送失败写入告警日志;密码登录作为保底方式(非单一入口);建议配置备用短信服务商通道 |
|
||||
| 多端同时登录同一账号 | 高(日常场景) | 低 | 本期允许,后续如需踢出,可在 Token 机制中引入版本号 |
|
||||
| 滑块验证被机器模拟轨迹绕过 | 低 | 高 | 服务端综合位置 + 轨迹特征校验;后续可引入设备指纹加固 |
|
||||
| Tenant Code 枚举攻击(暴力试探) | 低 | 中 | 接口限流 + 统一外显文案,不区分「未找到」与「已禁用」 |
|
||||
| 密码重置凭证泄露 | 低 | 高 | 一次性、短时效、HTTPS 传输 |
|
||||
| 短信服务故障 | 中 | 高 | 失败告警 + 密码登录保底 + 建议配置备用短信通道 |
|
||||
| 多端同时登录同一账号 | 高(日常场景) | 低 | 本期允许,后续如需踢出再做版本号机制 |
|
||||
|
||||
### 6.4 开放问题(开发前需确认)
|
||||
### 7.3 开放问题(开发前需确认)
|
||||
|
||||
- [ ] **短信服务商选型**:使用阿里云短信 / 腾讯云短信 / 其他服务商?需运维确认并提前申请短信签名和模板审核(国内审核周期 1–3 个工作日)— 负责人:后端负责人 — 截止:开发启动前
|
||||
- [ ] **Session 有效期默认值**:8 小时是否满足各租户需求?是否允许租户管理员自行配置?— 负责人:产品经理 — 截止:开发启动前
|
||||
- [ ] **滑块拼图实现方案**:自研(Pillow 生成图片 + 前端拖拽组件)还是集成第三方行为验证服务(如极验 GeeTest / 网易易盾)?自研可控但需维护图库;第三方开箱即用但引入外部依赖,需评估数据合规要求 — 负责人:后端负责人 + 安全 — 截止:开发启动前
|
||||
- [ ] **账号锁定通知**:账号被锁定后,是否自动发短信通知用户和/或通知管理员(站内消息)?— 负责人:产品经理 — 截止:开发启动前
|
||||
- [ ] **短信服务商选型**:阿里云 / 腾讯云 / 其他?短信签名与模板审核需要 1–3 个工作日 — 负责人:后端负责人 — 截止:开发启动前
|
||||
- [ ] **Session 默认有效期**:8 小时是否满足各租户需求?是否允许 Tenant Admin 自行配置?— 负责人:产品经理 — 截止:开发启动前
|
||||
- [ ] **滑块拼图实现方案**:自研还是集成第三方行为验证服务?需评估数据合规要求 — 负责人:后端负责人 + 安全 — 截止:开发启动前
|
||||
- [ ] **账号锁定通知**:账号被锁定后,是否自动发短信通知用户和/或通知管理员?— 负责人:产品经理 — 截止:开发启动前
|
||||
- [ ] **历史密码校验范围**:最近 3 次是否足够?是否需要额外规则(如不能与用户名相同)?— 负责人:产品经理 — 截止:开发启动前
|
||||
|
||||
---
|
||||
|
||||
## 7. 发布计划
|
||||
## 8. 发布计划
|
||||
|
||||
| 阶段 | 时间 | 受众 | 准入门槛 |
|
||||
|------|------|------|---------|
|
||||
@@ -630,49 +633,50 @@ Response 200 (失败):
|
||||
|
||||
---
|
||||
|
||||
## 8. 附录
|
||||
## 9. 附录
|
||||
|
||||
### 8.1 登录状态流转图
|
||||
### 9.1 登录状态流转图
|
||||
|
||||
```
|
||||
[未识别 Tenant]
|
||||
│ 输入有效 Tenant Code
|
||||
↓
|
||||
[未登录]
|
||||
│ 账密登录成功
|
||||
│ 账密 / 验证码登录成功
|
||||
↓
|
||||
[初始密码状态](如账号为初始密码)
|
||||
│ 强制修改密码成功
|
||||
│ 强制改密成功
|
||||
↓
|
||||
[已登录 - Active Session]
|
||||
│ Session 过期 / 主动登出 / 管理员强制登出
|
||||
↓
|
||||
[未登录](跳转登录界面)
|
||||
[未登录](跳转登录页)
|
||||
|
||||
[账号锁定状态](5次错误后)
|
||||
│ 30 分钟后自动解锁 或 管理员手动解锁
|
||||
[账号锁定状态](密码连续错误达到阈值后)
|
||||
│ 锁定时长结束自动解锁 或 管理员手动解锁
|
||||
↓
|
||||
[未登录](可重新登录)
|
||||
```
|
||||
|
||||
### 8.2 接口清单汇总
|
||||
### 9.2 业务能力清单(替代原"接口清单")
|
||||
|
||||
| 接口 | 方法 | Schema 位置 | 是否需要鉴权 | 说明 |
|
||||
|------|------|------------|------------|------|
|
||||
| `/api/auth/tenant/verify/` | POST | Public(shared) | 否 | Tenant Code 验证 |
|
||||
| `/api/auth/captcha/` | GET | Tenant | 否 | 获取滑块拼图验证码(返回背景图 Base64 + 碎片图 Base64 + 验证 Token) |
|
||||
| `/api/auth/captcha/verify/` | POST | Tenant | 否 | 提交滑动轨迹 + 位置,服务端校验并返回一次性通过凭证(供登录接口使用) |
|
||||
| `/api/auth/login/` | POST | Tenant | 否 | 手机号 + 密码登录 |
|
||||
| `/api/auth/login/phone/` | POST | Tenant | 否 | 手机号 + 短信验证码登录(MVP 正式功能) |
|
||||
| `/api/auth/logout/` | POST | Tenant | 是 | 登出,使 Session 失效 |
|
||||
| `/api/auth/recover/password/request/` | POST | Tenant | 否 | 发起找回密码(发送短信验证码) |
|
||||
| `/api/auth/recover/password/verify/` | POST | Tenant | 否 | 校验短信验证码,颁发一次性 `sms_reset_token` |
|
||||
| `/api/auth/recover/password/reset/` | POST | Tenant | 否(Token 鉴权) | 提交新密码 |
|
||||
| `/api/auth/wechat/qrcode/` | GET | Tenant | 否 | **预留 v2**,获取微信二维码 |
|
||||
| `/api/auth/wechat/callback/` | POST | Tenant | 否 | **预留 v2**,微信扫码回调 |
|
||||
> 本文件不再列出具体接口路径与 HTTP 方法。完整 API 端点清单(含路径、方法、Schema 位置、是否鉴权、预留端点)请查阅 `TECH_STACK/登录管理技术方案.md` §五。
|
||||
|
||||
### 8.3 相关文档参考
|
||||
| 业务能力 | 提供给谁 | 说明 |
|
||||
|---|---|---|
|
||||
| Tenant 识别 | 客户端 | 输入 12 位 Tenant Code,返回租户品牌与登录入口 |
|
||||
| 获取/校验滑块验证码 | 登录页 | 行为验证码生成与校验,输出一次性通过凭证 |
|
||||
| 密码登录 | 已识别租户的用户 | 手机号 + 密码 + 滑块凭证完成认证 |
|
||||
| 验证码登录 | 已识别租户的用户 | 手机号 + 短信验证码完成认证(需先通过滑块再获取验证码) |
|
||||
| 登出 | 已登录用户 | 销毁服务端会话与本地登录凭证 |
|
||||
| 找回密码(三步) | 忘记密码的用户 | 发送 OTP → 校验 OTP → 设置新密码 |
|
||||
| 首次登录强制改密 | 处于初始密码状态的用户 | 强制流程,提交后脱离初始密码状态 |
|
||||
| 微信扫码登录(v2 预留) | 全量用户 | MVP 仅展示禁用入口,v2 实现 |
|
||||
|
||||
- 技术栈文档:`Project/fonrey/TECH_STACK/TECH_STACK.md`
|
||||
- **登录管理数据模型**:`Project/fonrey/DATA_MODEL/DATA_MODEL_LOGIN.md`
|
||||
- **登录管理技术方案**:`Project/fonrey/TECH_STACK/登录管理技术方案.md`
|
||||
### 9.3 相关文档参考
|
||||
|
||||
- 技术栈总纲:`TECH_STACK/TECH_STACK.md`
|
||||
- **登录管理技术方案(实现口径权威)**:`TECH_STACK/登录管理技术方案.md`
|
||||
- **登录管理数据模型(数据口径权威)**:`DATA_MODEL/DATA_MODEL_LOGIN.md`
|
||||
- 全局 API 契约:`TECH_STACK/API_CONTRACT.md`
|
||||
- ADR:`ADR.md`(特别是 `ADR-20260502-003` PRD/Tech 职责边界、`ADR-20260430-004` 登录接口路径同步规则)
|
||||
|
||||
@@ -1,670 +0,0 @@
|
||||
# PRD:系统管理模块(Admin & System Management)
|
||||
|
||||
**状态**:Draft
|
||||
**作者**:产品经理
|
||||
**最后更新**:2026-05-01
|
||||
**版本**:v1.3
|
||||
**利益相关方**:工程负责人、运营团队、安全合规、客户成功团队
|
||||
|
||||
## 变更历史
|
||||
|
||||
| 版本 | 日期 | 作者 | 变更说明 |
|
||||
|------|------|------|---------|
|
||||
| v1.0 | 2026-04-24 | 产品经理 | 初稿 |
|
||||
| v1.1 | 2026-05-01 | 产品经理 | ① Story 1 补充「默认配置」内容定义(权限定义 + 系统默认角色);② Story 1 补充欢迎通知机制(邮件内容规范、默认密码发放、Tenant Code、页面下载 PDF);③ Story 2 补充 License 时效管理(到期自动挂起、提前 15 天预警倒计时);④ Story 3 标注为已废弃(暂不实现);⑤ 新增 Story 7:平台版本总览(基础数据版本 + 租户数据升级版本);⑥ §5.1.1 补充默认配置内容说明、通知机制细节、时效日期字段、到期挂起流程;⑦ 管理员角色权限矩阵补充版本总览权限 |
|
||||
| v1.3 | 2026-05-01 | 产品经理 | Story 1 Tenant Admin 权限机制修正:初始 Tenant Admin 不赋予任何业务角色,由系统在租户创建时直接写入独立的「租户管理员」专属权限集合;该集合不在角色管理界面显示,不可自行修改或分配;新增/变更租户管理员须由平台运营方操作 |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 1. 问题陈述
|
||||
|
||||
### 1.1 背景
|
||||
|
||||
Fonrey 是一套面向房产经纪公司的 B2B SaaS 平台,采用 `django-tenants` 实现 PostgreSQL Schema 级别的多租户隔离。随着平台商业化推进,运营团队需要一套独立的管理后台(Admin Console)来管理租户生命周期、系统升级、备份恢复及合规审计。
|
||||
|
||||
**本模块解决的核心问题**:平台运营团队当前缺乏统一的工具来:
|
||||
1. 管理数百家经纪公司(租户)的开通、暂停、注销流程
|
||||
2. 在不中断服务的前提下对平台进行版本升级与灰度发布
|
||||
3. 应对数据灾难场景(数据误删、升级失败)时快速恢复
|
||||
4. 满足合规要求,对所有高危操作留存完整审计轨迹
|
||||
|
||||
### 1.2 核心痛点
|
||||
|
||||
| 痛点 | 影响方 | 当前代价 |
|
||||
|------|--------|---------|
|
||||
| 无统一租户管理界面,开通/暂停操作依赖人工脚本 | 运营团队 | 高错误风险,操作耗时 |
|
||||
| 版本升级需停机维护,影响所有租户 | 所有用户 | SLA 违约风险 |
|
||||
| 数据备份无策略,灾难恢复依赖人工 | 平台稳定性 | 数据丢失风险 |
|
||||
| 高危操作无审计日志,合规风险暴露 | 管理层/合规 | 法律与客户信任风险 |
|
||||
|
||||
### 1.3 目标用户
|
||||
|
||||
| 角色 | 使用场景 | 频率 |
|
||||
| --------------------------- | ----------- | ------ |
|
||||
| Platform Admin(平台超级管理员)(Platform Super Admin) | 全局配置、高危操作授权 | 低频(每周) |
|
||||
| 运维人员(Ops Operator) | 日常租户管理、监控巡检 | 高频(每日) |
|
||||
| 只读审计员(Read-only Auditor) | 日志查询、合规报告导出 | 中频(每周) |
|
||||
|
||||
---
|
||||
|
||||
## 2. 目标与成功指标
|
||||
|
||||
| 目标 | 指标 | 当前基线 | 目标值 | 测量窗口 |
|
||||
| -------- | ----------- | ----------- | --------------- | -------- |
|
||||
| 租户管理效率提升 | 新租户开通耗时 | 人工脚本 ~30 分钟 | < 5 分钟(含自动初始化) | 上线后 30 天 |
|
||||
| 平台升级零停机 | 升级期间受影响租户数 | 全量中断 | 灰度阶段受影响 ≤ 5% 租户 | 每次升级 |
|
||||
| 数据恢复能力建立 | RTO(恢复时间目标) | 无标准流程 | 单租户恢复 < 2 小时 | v1 上线即达标 |
|
||||
| 操作合规覆盖 | 高危操作审计日志覆盖率 | 0% | 100% | 上线后 30 天 |
|
||||
| 管理员安全 | MFA 启用率 | 0% | 100%(强制) | 上线即达标 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 非目标(Non-Goals)
|
||||
|
||||
- **不在 v1 实现**:自动化账单计费、多币种支持、Webhook 自定义集成市场
|
||||
- **不在本模块**:租户内业务权限的细粒度配置(见权限管理模块 PRD)
|
||||
- **不在本模块**:客服工单系统、SLA 自动赔付
|
||||
- **不支持**:移动端浏览器(管理后台仅面向桌面,运营人员使用场景明确)
|
||||
|
||||
---
|
||||
|
||||
## 4. 用户角色与核心故事
|
||||
|
||||
### Persona A:运营人员 Lily(日常租户管理)
|
||||
|
||||
> 负责 Fonrey 平台的日常运营,每天需要处理新客户开通、异常租户处理、客户咨询的数据导出请求,使用 PC 浏览器访问管理后台。
|
||||
|
||||
**Story 1**:新租户开通
|
||||
|
||||
> 作为运营人员,我希望通过填写表单快速完成租户开通,并由系统自动完成数据库初始化与欢迎邮件,无需手动执行脚本。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 表单提交后,系统在后台自动创建 PostgreSQL Schema 并注入默认配置(见 §5.1.1 默认配置说明),完成时间 < 60 秒
|
||||
- [ ] 默认配置注入包含两部分:**(1)权限定义(PermissionDef)**:注入该平台所有权限码的定义数据(`permission_code`、描述、模块归属),作为该租户 RBAC 权限体系的基础;**(2)系统默认角色与权限绑定**:按「角色权限矩阵.md」定义注入 7 个系统内置业务角色——置业顾问、店管、区管、区总、副总、总经、其他职能——并完成各角色对应的权限集合绑定
|
||||
- [ ] 初始 Tenant Admin 用户(以联系人手机号创建)**不通过业务角色赋权**,而是在租户创建时由系统直接写入「租户管理员」专属权限集合;该权限集合独立于 7 个业务角色之外,不在租户的角色管理界面中显示,不可由 Tenant Admin 自行修改或分配给其他用户;如需新增或变更租户管理员,须由平台运营方在管理后台操作
|
||||
- [ ] 新租户创建后,平台运营管理员收到系统内通知(站内消息);租户联系人收到欢迎邮件(见下方「欢迎邮件规范」)
|
||||
- [ ] 若联系人无邮箱,运营人员可在租户详情页下载「入驻信息 PDF 文档」,通过微信等渠道手动转发
|
||||
- [ ] 租户访问地址采用 Fonrey 平台统一域名 + Tenant Code 参数的形式(如 `https://app.fonrey.com/?tenant=ABCD`),无需为每个租户单独创建子域名;租户详情页展示该访问链接,可一键复制
|
||||
- [ ] 创建失败时回滚所有已创建资源,并显示明确的错误原因
|
||||
|
||||
**欢迎邮件规范**(联系人有邮箱时自动发送):
|
||||
|
||||
| 字段 | 内容 |
|
||||
| ---- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| 主题 | 【房睿平台】您的账号已开通,欢迎登录 |
|
||||
| 收件人 | 租户联系人邮箱 |
|
||||
| 正文内容 | 公司名称、**Tenant Code**(登录时所需的租户识别码)、登录地址(`https://app.fonrey.com/?tenant={Tenant Code}`)、Tenant Admin 手机号(脱敏展示后三位)、**系统初始密码**(明文,首次登录后强制修改)、平台客服联系方式 |
|
||||
| 备注 | 初始密码由系统随机生成(12 位,含大小写字母+数字),发送后立即标记为「首次登录强制修改」状态 |
|
||||
|
||||
**入驻信息 PDF 文档**(可在租户详情页下载,适用于无邮箱客户):
|
||||
|
||||
- 包含与欢迎邮件相同的所有关键信息
|
||||
- 页面入口:租户详情 → 基本信息 Tab → 「下载入驻信息」按钮
|
||||
- 文件名格式:`{公司名称}_入驻信息_{日期}.pdf`
|
||||
|
||||
**Story 2**:挂起问题租户
|
||||
|
||||
> 作为运营人员,我希望能快速冻结欠费租户的访问,同时保证数据不丢失,并在欠费解决后一键恢复。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 挂起操作执行后,该租户所有用户登录跳转至"账号已暂停"提示页,管理后台数据访问不受影响
|
||||
- [ ] 支持设置到期时间,到期后系统自动恢复租户状态,并发送通知邮件
|
||||
- [ ] 所有挂起/恢复操作记录于操作审计日志,包含操作人、时间、原因
|
||||
|
||||
**Story 2b**:License 时效管理与到期自动挂起
|
||||
|
||||
> 作为 Platform Admin,我希望每个租户能够设置 License 有效期,在到期后系统自动挂起租户,并在到期前提前预警,减少人工干预。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 每个租户的「基本信息」中包含 **License 到期日期**字段,由 Platform Admin 在创建租户或套餐续费时设定(如购买 1 年期 License)
|
||||
- [ ] 系统(Celery Beat 每日检查)在 License 到期时自动将租户状态切换为「已挂起 Suspended」,挂起原因标注为「License 到期」
|
||||
- [ ] 自动挂起后,租户联系人收到通知邮件;Platform Admin 可手动解除挂起(续费后操作)
|
||||
- [ ] **提前 15 天预警倒计时**:租户内的 Tenant Admin 在登录后的管理界面顶部看到醒目横幅提示,内容示例:「您的 License 将于 X 天后到期({到期日期}),请联系平台续费。」;提前 15 天开始出现,每天展示直至到期或续费完成
|
||||
- [ ] 倒计时横幅仅对租户端 Tenant Admin 可见,不影响普通 Agent 用户体验(可配置)
|
||||
- [ ] License 到期日期在管理后台租户列表和详情页均可见,支持按「即将到期(15 天内)」筛选
|
||||
|
||||
**Story 3**:响应客户数据导出请求
|
||||
|
||||
> **状态**:暂缓(当前 P0 计划阶段不实现,后续迭代规划)。本 Story 保留需求描述,待进入相应排期后正式细化。
|
||||
|
||||
---
|
||||
|
||||
### Persona B:Platform Admin(平台超级管理员) David(系统升级与回滚)
|
||||
|
||||
> 负责平台技术运维,周期性执行版本升级,关注升级稳定性与租户影响面,有权执行所有高危操作。
|
||||
|
||||
**Story 4**:灰度系统升级
|
||||
|
||||
> 作为Platform Admin(平台超级管理员),我希望先对内测租户升级新版本,验证稳定后再全量推送,避免一次性影响所有客户。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 升级前自动执行健康检查,存在异常服务时阻断升级并提示
|
||||
- [ ] 支持指定目标租户进行灰度升级,灰度租户名单可编辑
|
||||
- [ ] 升级过程实时展示进度(每个租户的升级状态),支持查看升级日志
|
||||
- [ ] 升级失败时系统自动告警,并提供一键回滚入口
|
||||
|
||||
**Story 5**:升级失败回滚
|
||||
|
||||
> 作为Platform Admin(平台超级管理员),我希望在升级出现问题时能立即回滚至上一稳定版本,并生成事件报告。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 回滚操作触发前自动保存当前状态快照
|
||||
- [ ] 支持全量回滚或单租户回滚
|
||||
- [ ] 回滚完成后生成事件报告:失败原因、回滚耗时、影响范围
|
||||
- [ ] 回滚操作需二次身份验证确认
|
||||
|
||||
---
|
||||
|
||||
### Persona C:只读审计员 Carol(合规审计)
|
||||
|
||||
> 负责平台合规审查,定期导出操作日志供法务或客户审查,无任何写权限。
|
||||
|
||||
**Story 6**:审计日志查询与导出
|
||||
|
||||
> 作为审计员,我希望能按操作人、时间范围、操作类型筛选操作日志,并导出为报告格式。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 日志列表支持多维度筛选:操作人、时间范围、操作对象、操作类型(创建/修改/删除/高危操作)
|
||||
- [ ] 日志条目包含:操作人、操作时间、操作对象(租户/用户ID)、操作内容摘要、操作结果(成功/失败)、操作来源 IP
|
||||
- [ ] 支持导出筛选结果为 CSV 格式
|
||||
|
||||
---
|
||||
|
||||
### Persona D:Platform Admin(平台超级管理员)David(平台版本总览)
|
||||
|
||||
**Story 7**:查看平台与租户版本总览
|
||||
|
||||
> 作为 Platform Admin,我希望能在管理界面一眼看到整个平台的版本情况,包括基础数据版本和每个租户各自的数据升级版本,以便掌握升级进度和版本差异。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 管理控制台「系统版本管理」页面提供「版本总览」视图,分为两个部分:
|
||||
|
||||
**Part 1:平台基础数据版本**
|
||||
- 展示当前平台基础数据(公共 Schema 中的 PermissionDef、系统配置等 seed 数据)的版本号
|
||||
- 该版本对所有租户一致,每次平台升级为一次性全量升级
|
||||
- 展示字段:版本号、最后升级时间、升级描述、升级执行人
|
||||
|
||||
**Part 2:租户数据升级版本**
|
||||
- 以列表形式展示每个租户当前的数据版本号(即该租户 Schema 已完成的 migration 版本)
|
||||
- 由于采用灰度升级,各租户版本号可能不一致
|
||||
- 列表字段:租户名称、当前数据版本号、上次升级时间、升级状态(最新 / 待升级 / 升级中 / 升级失败)
|
||||
- 支持按「待升级」「升级失败」筛选,快速定位异常租户
|
||||
- 点击租户行可跳转至该租户详情的「备份记录」Tab 查看详情
|
||||
|
||||
- [ ] 页面支持手动刷新版本状态
|
||||
- [ ] 「版本总览」数据展示无需实时,允许最多 5 分钟缓存延迟
|
||||
|
||||
---
|
||||
|
||||
**Story 8**:查看与控制租户用户数
|
||||
|
||||
> 作为 Platform Admin,我希望能在管理界面看到每个租户当前的用户数量,并能设置用户数上限,以便根据 License 授权进行管控(用户数是 License 计费的重要依据)。
|
||||
|
||||
**验收标准**:
|
||||
- [ ] 租户列表新增「当前用户数」列,显示该租户当前已创建的有效用户总数(含 Tenant Admin + 所有 Agent,不含已删除/离职用户)
|
||||
- [ ] 租户详情页「基本信息」Tab 显示:当前用户数 / License 授权用户数上限(如:12 / 50)
|
||||
- [ ] Platform Admin 可在租户详情页设置「License 授权用户数上限」字段;当租户实际用户数达到上限时,Tenant Admin 在该租户内将无法继续创建新用户,并收到提示:「当前用户数已达 License 上限,请联系平台扩容」
|
||||
- [ ] Platform Admin 可随时调整用户数上限(续费扩容 or 缩容),变更记录写入操作审计日志
|
||||
- [ ] 租户列表支持按「用户数已满(≥ 上限)」筛选,便于平台运营主动识别需要续费的租户
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
### 5.1 租户管理(Tenant Management)
|
||||
|
||||
#### 5.1.1 租户生命周期
|
||||
|
||||
**新建租户**
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 公司名称 | Text | ✅ | 最大 100 字符 |
|
||||
| 联系人 | Text | ✅ | 租户主联系人姓名 |
|
||||
| 联系邮箱 | Email | ❌(可选) | 用于发送欢迎邮件及系统通知;无邮箱时改用 PDF 下载方式 |
|
||||
| 所在地区 | Select | ✅ | 省市两级 |
|
||||
| 订阅套餐 | Select | ✅ | Basic / Professional / Enterprise |
|
||||
| 子域名 | Text | ❌(无需) | 租户访问统一使用 Fonrey 平台域名 + Tenant Code 参数,无子域名 |
|
||||
| License 到期日期 | Date | ✅ | 由 Platform Admin 设定,决定租户有效期;到期后系统自动挂起 |
|
||||
|
||||
创建流程:
|
||||
1. 表单校验通过后,后台 Celery 任务执行:
|
||||
- 创建 PostgreSQL Schema(`tenant_{id}`)
|
||||
- 执行 Migrate 初始化表结构
|
||||
- 注入默认配置(见下方「默认配置内容」说明)
|
||||
- 生成初始密码(12 位随机,含大小写字母+数字),标记为「首次登录强制修改」
|
||||
- 若联系邮箱已填写:发送欢迎邮件(含 Tenant Code、初始密码、平台访问链接 `https://app.fonrey.com/?tenant={TenantCode}`)
|
||||
2. 任务完成后更新租户状态为 `active`,失败则全量回滚并标记为 `failed`
|
||||
3. 生成唯一 Tenant ID(UUID)及 Tenant Code(可读短码,如 `FR-2024-0001`),记录创建时间、创建人
|
||||
|
||||
**默认配置内容(Schema 初始化时注入)**:
|
||||
|
||||
| 配置类型 | 内容 | 说明 |
|
||||
|---------|------|------|
|
||||
| 权限定义(PermissionDef) | 平台全量权限码(`permission_code`、描述、模块归属) | 从 public schema 同步至租户 schema,作为 RBAC 权限体系基础 |
|
||||
| 系统默认角色 | Tenant Admin(租户管理员)、Agent(经纪人) | 按权限管理模块 PRD 定义的权限集合完成角色-权限绑定 |
|
||||
| 初始 Tenant Admin 用户 | 以联系人手机号创建,角色为 Tenant Admin | 首次登录后强制修改密码 |
|
||||
|
||||
**挂起(Suspend)**
|
||||
|
||||
- 操作触发条件:
|
||||
- **手动触发**:运营人员手动触发,选择挂起原因(欠费 / 违规 / 主动申请 / 其他)
|
||||
- **自动触发**:Celery Beat 每日检查 License 到期日期,到期后自动挂起(原因标注为「License 到期」)
|
||||
- 可设置挂起到期时间(留空表示永久挂起直至手动恢复)
|
||||
- 挂起效果:该租户所有用户请求返回 `HTTP 403`,重定向至暂停提示页;管理后台数据仍可访问
|
||||
- 到期自动恢复:`Celery Beat` 定时检查到期挂起记录,自动切换状态为 `active`(仅适用于手动设置了到期时间的挂起;License 到期自动挂起需 Platform Admin 手动恢复)
|
||||
- 通知:挂起与恢复均向租户联系邮箱发送通知邮件(无邮箱则跳过)
|
||||
- **License 到期预警**:License 到期前 15 天起,租户端 Tenant Admin 管理界面顶部显示倒计时横幅,直至到期或续费后由 Platform Admin 更新 License 到期日期
|
||||
|
||||
**删除(Delete)**
|
||||
|
||||
| 模式 | 说明 |
|
||||
|------|------|
|
||||
| 软删除(Soft Delete) | 标记删除状态,数据保留 30 天(默认,可配置)后由 Celery 定时任务清除 |
|
||||
| 硬删除(Hard Delete) | 立即清除所有数据、Schema、存储资源及子域名授权;仅Platform Admin(平台超级管理员)可操作 |
|
||||
|
||||
删除前置条件:
|
||||
1. 操作人必须确认数据导出已完成(勾选确认框)
|
||||
2. 硬删除需二次身份验证(MFA 确认)
|
||||
3. 软删除冷静期内(默认 30 天),可在租户列表中对已删除租户执行"撤销删除"
|
||||
|
||||
删除完成后:释放子域名、Cloudflare R2 存储桶、License 席位
|
||||
|
||||
#### 5.1.2 数据管理
|
||||
|
||||
**数据导出**
|
||||
|
||||
- 触发方式:管理员手动触发,选择目标租户 + 导出模块 + 格式
|
||||
- 异步执行:Celery 任务,任务状态实时刷新(Pending → In Progress → Done / Failed)
|
||||
- 导出包内容:结构化数据(CSV / JSON / SQL Dump)+ 文件资产 URL 清单,**不打包文件实体**
|
||||
- 导出模块选项:客户数据 / 房源数据 / 交易记录 / 系统配置 / 全量
|
||||
- 导出包存储:压缩后存于 Cloudflare R2 临时目录,生成带签名下载链接,有效期 24 小时
|
||||
|
||||
**文件资产(图片/附件)的导出处理规则**
|
||||
|
||||
> **设计决策**:v1 不打包文件实体,文件以 CDN 持久 URL 形式内嵌于导出数据中。
|
||||
> 依据:R2 Bucket 配置为 public read,文件通过 Cloudflare CDN 对外提供持久访问;
|
||||
> 在租户账号未被硬删除的情况下,CDN URL 始终有效,满足合规/审计场景需求。
|
||||
> 迁移场景(需要文件实体)走"完整备份"流程,不走"数据导出"流程。
|
||||
|
||||
各导出格式的文件字段表达方式:
|
||||
|
||||
| 导出格式 | 图片字段示例 | 附件字段示例 |
|
||||
|---------|------------|------------|
|
||||
| CSV | `photos` 列:多个 CDN URL 以英文分号分隔 | `attachments` 列:`文件名\|CDN URL` 以分号分隔 |
|
||||
| JSON | `"photos": [{"url": "https://cdn.../xxx.jpg", "filename": "封面.jpg", "created_at": "..."}]` | `"attachments": [{"url": "...", "filename": "合同.pdf"}]` |
|
||||
| SQL Dump | 文件元数据表原样导出,`file_url` 字段为 CDN URL | 同左 |
|
||||
|
||||
导出包内附说明文件(`README.txt`),注明:
|
||||
> "图片与附件以 Cloudflare CDN 链接形式提供,链接在账号有效期内持续可访问。账号注销后链接将在 30 天冷静期结束时失效。如需迁移文件本体,请联系平台支持发起完整数据备份(Backup)。"
|
||||
|
||||
**数据导出 vs 完整备份的边界**
|
||||
|
||||
| 维度 | 数据导出(Export) | 完整备份(Backup) |
|
||||
|------|------------------|-----------------|
|
||||
| 用途 | 合规审计、数据核查、业务分析 | 灾难恢复、租户迁移 |
|
||||
| 文件资产 | CDN URL 清单,不含文件实体 | 含 R2 文件实体(完整同步) |
|
||||
| 完成时间 | 分钟级 | 小时级(取决于文件总量) |
|
||||
| 触发方式 | 运营人员手动触发 | 手动触发 / 系统自动触发(升级前) |
|
||||
| 存储成本 | 极低(仅压缩包) | 较高(完整文件副本) |
|
||||
|
||||
**数据备份(Snapshot)**
|
||||
|
||||
- 自动触发:升级前系统自动触发该租户全量备份
|
||||
- 手动触发:管理员可在租户详情页手动发起备份
|
||||
- 备份内容:数据库 Schema(pg_dump)+ Cloudflare R2 文件存储(附件、图片)
|
||||
- 备份记录展示字段:备份时间、触发方式(自动/手动)、备份大小、状态(进行中/成功/失败)
|
||||
- 保留策略:默认保留最近 10 个版本,可在系统全局配置中调整
|
||||
- 存储:加密存储,支持目标存储配置(本地 / S3 / Cloudflare R2 / GCS)
|
||||
|
||||
**数据恢复(Restore)**
|
||||
|
||||
恢复流程:
|
||||
|
||||
```
|
||||
选择目标备份版本
|
||||
→ 二次确认弹窗(显示将覆盖的当前数据版本信息)
|
||||
→ 自动对当前数据生成临时快照(防止恢复失误)
|
||||
→ 租户切换为维护模式(用户访问显示"维护中"提示)
|
||||
→ 执行数据恢复(Celery 任务)
|
||||
→ 恢复完成 → 自动恢复服务 → 生成恢复操作报告
|
||||
```
|
||||
|
||||
恢复操作报告包含:操作人、操作时间、恢复前数据版本、恢复后数据版本、耗时、结果
|
||||
|
||||
#### 5.1.3 套餐与升级管理
|
||||
|
||||
**Plan 升级**
|
||||
|
||||
- 支持升级路径:Basic → Professional → Enterprise
|
||||
- 升级前展示差异对比表(功能项、用户数上限、存储空间、API 调用额度)
|
||||
- 生效模式:立即生效 / 按账期生效(下一个账期开始时生效)
|
||||
- 升级前自动触发数据备份
|
||||
- 升级失败:提供一键回滚至备份版本
|
||||
- 升级历史记录:时间、操作人、升级前套餐、升级后套餐
|
||||
|
||||
#### 5.1.4 用户与权限管理
|
||||
|
||||
**Tenant Admin 管理**
|
||||
|
||||
- 每个租户可设置 1 至多名 Tenant Admin(超级用户)
|
||||
- Platform Admin(平台超级管理员)可直接在后台创建新用户并赋予 Tenant Admin 角色,或从租户现有用户中指定
|
||||
- 支持查看当前 Tenant Admin 列表,执行:新增 / 替换 / 撤销权限
|
||||
|
||||
**Tenant Admin 权限配置(RBAC)**
|
||||
|
||||
可配置权限项:
|
||||
|
||||
| 权限项 | 说明 |
|
||||
|--------|------|
|
||||
| 创建/删除子用户 | 是否允许 Tenant Admin 管理租户内部用户 |
|
||||
| 修改系统配置 | 是否允许修改租户级系统设置(字段标签、规则等) |
|
||||
| 查看账单与套餐 | 是否允许查看订阅信息和费用详情 |
|
||||
| 数据导出 | 是否允许在租户端触发数据导出 |
|
||||
|
||||
权限基于 RBAC 模型,支持自定义角色(角色名称 + 权限集合),可在多 Tenant Admin 间复用。
|
||||
|
||||
**密码重置**
|
||||
|
||||
- Platform Admin(平台超级管理员)可为任意租户的任意用户发起密码重置
|
||||
- 方式一:发送重置链接至注册邮箱(用户自助重置)
|
||||
- 方式二:管理员直接设置临时密码(用户首次登录后强制修改)
|
||||
- 所有重置操作记录于操作审计日志
|
||||
|
||||
#### 5.1.5 租户监控与统计
|
||||
|
||||
**资源监控**
|
||||
|
||||
实时展示指标(基于 Grafana + 自定义数据采集):
|
||||
|
||||
| 指标 | 展示维度 |
|
||||
|------|---------|
|
||||
| CPU / 内存占用 | 实时折线图 |
|
||||
| 存储用量 | 当前值 vs 套餐上限 |
|
||||
| API 调用次数 | 当日 / 本月累计 |
|
||||
| 活跃用户数 | 当日活跃数 |
|
||||
| 当日登录次数 | 累计折线图 |
|
||||
| 异常请求数 | 4xx / 5xx 分类 |
|
||||
| 慢查询数量 | > 500ms 查询次数 |
|
||||
|
||||
告警配置:支持为每个关键指标设置阈值,超限时触发邮件 / Webhook 通知。
|
||||
|
||||
**可用性统计(Availability / SLA)**
|
||||
|
||||
- 服务可用率(Uptime)统计:支持日 / 周 / 月维度
|
||||
- 故障事件记录:开始时间、恢复时间、持续时长、影响描述
|
||||
- SLA 达标率报告:可导出供客户成功团队使用
|
||||
|
||||
---
|
||||
|
||||
### 5.2 系统管理(System Management)
|
||||
|
||||
#### 5.2.1 版本升级与回滚
|
||||
|
||||
**系统升级流程**
|
||||
|
||||
```
|
||||
上传/拉取升级包(制品库 Artifact Registry)
|
||||
→ 系统自动健康检查(所有服务状态正常才允许继续)
|
||||
→ 配置升级策略:全量 / 灰度(指定内测租户列表)
|
||||
→ 升级前自动备份(对所有参与本次升级的租户)
|
||||
→ 执行升级
|
||||
→ 实时展示升级进度(租户维度状态列表)
|
||||
→ 升级完成通知(成功/失败详情)
|
||||
```
|
||||
|
||||
**灰度升级策略**:
|
||||
|
||||
- 维护"内测租户组"列表,由Platform Admin(平台超级管理员)配置
|
||||
- 灰度阶段仅对内测租户执行升级,其余租户保持原版本
|
||||
- 内测租户验证通过(手动确认)后,触发全量升级
|
||||
|
||||
**升级回滚**
|
||||
|
||||
- 触发条件:手动触发(管理员判断)或自动触发(监控检测到错误率超阈值)
|
||||
- 回滚范围:全量回滚(所有租户)/ 单租户回滚
|
||||
- 回滚前:自动保存当前状态快照
|
||||
- 回滚后:生成事件报告(失败原因、回滚耗时、受影响租户列表)
|
||||
- 执行回滚需二次身份验证
|
||||
|
||||
#### 5.2.2 定时备份策略
|
||||
|
||||
**全局备份计划**
|
||||
|
||||
| 配置项 | 选项 |
|
||||
|--------|------|
|
||||
| 备份频率 | 每小时 / 每日 / 每周 |
|
||||
| 执行时间 | 可配置时间窗口(默认每日 02:00) |
|
||||
| 保留数量 | 最近 N 个版本(默认 10) |
|
||||
| 存储目标 | 本地 / AWS S3 / Cloudflare R2 / GCS |
|
||||
|
||||
- 支持为单个租户配置独立备份计划,覆盖全局策略
|
||||
- 备份任务执行记录:开始时间、完成时间、备份大小、状态
|
||||
- 备份失败:自动告警 + 支持手动重试
|
||||
|
||||
---
|
||||
|
||||
### 5.3 管理控制台(Admin Console)
|
||||
|
||||
#### 5.3.1 核心页面规格
|
||||
|
||||
**仪表盘(Dashboard)**
|
||||
|
||||
| 模块 | 展示内容 |
|
||||
|------|---------|
|
||||
| 全局概览 | 总租户数、活跃租户数、本月新增租户数 |
|
||||
| 系统健康 | 各核心服务状态(Django / PostgreSQL / Redis / Celery / R2) |
|
||||
| 近期告警 | 最近 24 小时告警列表,按严重程度分类 |
|
||||
| 资源概览 | 平台整体存储用量、API 调用量趋势图 |
|
||||
| 最近操作 | 最近 10 条高危操作审计记录 |
|
||||
|
||||
**租户列表**
|
||||
|
||||
- 分页展示(默认 20 条/页)
|
||||
- 搜索:按公司名称、子域名、联系邮箱关键词搜索
|
||||
- 筛选:按状态(Active / Suspended / Deleted)、套餐(Basic/Pro/Enterprise)、注册时间范围、**即将到期(15 天内)**
|
||||
- 列表字段:公司名称、子域名、套餐、状态、注册时间、活跃用户数
|
||||
- 快捷操作:查看详情、挂起、发起备份、数据导出
|
||||
|
||||
**租户详情**
|
||||
|
||||
标签页结构:
|
||||
|
||||
| 标签 | 内容 |
|
||||
|------|------|
|
||||
| 基本信息 | 公司信息、联系人、子域名、套餐、状态,支持编辑部分字段 |
|
||||
| 用户管理 | Tenant Admin 列表、普通用户列表、密码重置入口 |
|
||||
| 套餐信息 | 当前套餐详情、用量统计、升级入口 |
|
||||
| 监控数据 | 该租户资源使用图表、SLA 统计 |
|
||||
| 备份记录 | 该租户备份列表、手动触发备份、恢复操作入口 |
|
||||
| 操作历史 | 该租户相关的所有管理员操作日志 |
|
||||
|
||||
**系统版本管理**
|
||||
|
||||
- 当前运行版本信息
|
||||
- 历史版本列表(版本号、发布时间、状态:Current / Previous / Archived)
|
||||
- 升级入口(上传/拉取升级包)
|
||||
- 回滚入口(选择目标版本)
|
||||
|
||||
**备份管理**
|
||||
|
||||
- 全局备份计划配置
|
||||
- 备份任务列表(支持按租户、状态、时间筛选)
|
||||
- 手动触发备份(选择租户)
|
||||
- 恢复操作入口
|
||||
|
||||
**监控与告警**
|
||||
|
||||
- 租户级 / 系统级监控图表(基于 Grafana iframe 嵌入或自定义实现)
|
||||
- 告警规则配置(指标 + 阈值 + 通知渠道)
|
||||
- 告警历史列表
|
||||
|
||||
**审计日志**
|
||||
|
||||
- 全平台操作日志,支持多维度筛选与导出
|
||||
- 每条日志包含:操作人、时间、操作对象、内容摘要、结果、来源 IP
|
||||
|
||||
**管理员设置**
|
||||
|
||||
- 管理员账号管理(创建、编辑、停用)
|
||||
- 角色配置(Platform Admin(平台超级管理员) / 运营人员 / 只读审计员)
|
||||
- MFA 设置(强制启用,支持 TOTP)
|
||||
- IP 白名单配置
|
||||
- 登录会话管理(查看活跃会话、强制登出)
|
||||
|
||||
#### 5.3.2 访问控制与安全
|
||||
|
||||
**强制要求(不可降级)**:
|
||||
|
||||
| 安全要求 | 实现方式 |
|
||||
|---------|---------|
|
||||
| MFA 强制启用 | 所有管理员账号首次登录强制配置 TOTP;无法跳过 |
|
||||
| IP 白名单 | 仅允许指定 IP 范围访问管理控制台 URL(Nginx 层或应用层限制) |
|
||||
| 高危操作二次验证 | 删除租户、数据恢复、系统回滚操作触发 MFA 二次确认弹窗 |
|
||||
| 会话超时 | 无操作 30 分钟后自动登出,Token 失效 |
|
||||
| 强制登出 | Platform Admin(平台超级管理员)可在"管理员设置"中强制终止指定管理员的所有会话 |
|
||||
|
||||
**与租户应用隔离**:
|
||||
|
||||
- 管理控制台部署在独立子域名(如 `admin.platform.com`),与租户应用域名体系分离
|
||||
- 管理控制台不共享租户应用的 Session / Cookie 机制
|
||||
|
||||
#### 5.3.3 操作审计日志规范
|
||||
|
||||
所有写操作(Create / Update / Delete)及高危操作必须记录审计日志,字段规范如下:
|
||||
|
||||
```python
|
||||
{
|
||||
"id": "UUID",
|
||||
"operator_id": "管理员用户 ID",
|
||||
"operator_name": "管理员显示名",
|
||||
"action_type": "CREATE_TENANT | SUSPEND_TENANT | DELETE_TENANT | RESTORE_DATA | SYSTEM_UPGRADE | ROLLBACK | RESET_PASSWORD | ...",
|
||||
"target_type": "Tenant | User | System | Backup",
|
||||
"target_id": "操作对象 ID",
|
||||
"target_name": "操作对象可读名称",
|
||||
"payload_summary": "操作内容摘要(非敏感字段)",
|
||||
"result": "SUCCESS | FAILED",
|
||||
"error_message": "失败原因(如有)",
|
||||
"ip_address": "操作来源 IP",
|
||||
"created_at": "ISO 8601 时间戳"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 技术考量
|
||||
|
||||
### 6.1 系统架构定位
|
||||
|
||||
基于 Fonrey 技术栈(Django + django-tenants + PostgreSQL + Celery + Cloudflare R2),管理控制台在同一 Django 项目中通过独立 App (`apps/admin_console/`) 实现,利用 Django 的 `public` Schema 作为管理控制台的数据层。
|
||||
|
||||
### 6.2 关键依赖
|
||||
|
||||
| 依赖 | 用途 | 风险等级 |
|
||||
|------|------|---------|
|
||||
| `django-tenants` | Schema 创建/销毁、租户切换 | 高 — 核心依赖,需确认 Schema 创建并发安全性 |
|
||||
| Celery + Celery Beat | 异步备份、导出、状态同步任务 | 中 — 需监控任务队列积压 |
|
||||
| PostgreSQL `pg_dump` | 数据备份与恢复 | 高 — 需测试大 Schema 备份耗时与锁表影响 |
|
||||
| Cloudflare R2 | 备份文件与导出文件存储 | 中 — 需评估大文件上传/下载带宽成本 |
|
||||
| Grafana | 监控图表展示 | 低 — 已在技术栈中规划 |
|
||||
| TOTP(如 `django-otp`) | MFA 实现 | 低 — 成熟库,接入成本低 |
|
||||
|
||||
### 6.3 已知风险
|
||||
|
||||
| 风险 | 可能性 | 影响 | 缓解措施 |
|
||||
|------|--------|------|---------|
|
||||
| 大租户 Schema 备份耗时超长(>1 小时) | 中 | 高 | 异步执行 + 进度追踪;评估流式备份方案 |
|
||||
| 系统升级过程中新请求涌入导致数据不一致 | 低 | 高 | 升级期间租户切换维护模式;使用数据库事务 |
|
||||
| 软删除数据保留期间存储成本积累 | 中 | 低 | 合理设置默认保留期,提供平台级存储用量监控 |
|
||||
| 管理控制台 IP 白名单配置错误导致运营团队被锁定 | 低 | 高 | 提供紧急访问恢复流程(通过服务器直接访问),文档化 |
|
||||
|
||||
### 6.4 待解决问题(开发启动前必须确认)
|
||||
|
||||
- [ ] **数据库备份方案**:`pg_dump` 直接执行还是基于 WAL 的增量备份(如 pgBackRest)?— Owner: 工程负责人 — Deadline: 技术评审前
|
||||
- [ ] **监控数据来源**:Grafana 直接对接 PostgreSQL 指标还是通过 Prometheus Exporter?— Owner: 运维团队
|
||||
- [ ] **MFA 库选型**:`django-otp` + TOTP 还是集成第三方认证(如 Okta)?— Owner: 工程负责人
|
||||
- [ ] **子域名管理机制**:Cloudflare DNS API 自动创建还是手动配置?— Owner: 运维团队
|
||||
- [ ] **审计日志存储**:写入 `public` Schema 还是独立日志服务(如 Elasticsearch)?— Owner: 工程负责人
|
||||
|
||||
---
|
||||
|
||||
## 7. 发布计划
|
||||
|
||||
| 阶段 | 时间 | 范围 | 通过标准 |
|
||||
|------|------|------|---------|
|
||||
| 内部 Alpha | Week 1–4 | 平台内部团队使用 | 核心租户 CRUD 流程无 P0 Bug;MFA 可用 |
|
||||
| 封闭 Beta | Week 5–6 | 运营团队日常使用 | 备份/恢复流程完整可用;审计日志 100% 覆盖 |
|
||||
| 正式上线 | Week 7 | 全量运营团队 | 升级/回滚流程验证通过;监控告警规则配置完成 |
|
||||
|
||||
**回滚标准**:若正式上线后 72 小时内发现租户数据隔离漏洞或审计日志丢失,立即回滚并进入 P0 修复流程。
|
||||
|
||||
---
|
||||
|
||||
## 8. 不构建清单(What We're NOT Building)
|
||||
|
||||
| 请求/功能 | 原因 | 重新评估条件 |
|
||||
|----------|------|------------|
|
||||
| 自动化账单与发票生成 | 超出本模块范围,财务模块独立立项 | 财务模块 PRD 完成后接入 |
|
||||
| 租户端自助迁移工具 | 当前用户规模不需要,运营团队手动处理即可 | 租户数 > 500 时重新评估 |
|
||||
| 移动端管理界面 | 运营团队使用场景明确为 PC,移动端收益低 | v2 规划,用户调研支持时推进 |
|
||||
| Webhook 事件推送市场 | 集成复杂度高,当前无客户需求驱动 | 有 3+ 客户明确需求时评估 |
|
||||
| 多语言管理界面 | 运营团队为内部人员,中文已满足需求 | 国际化扩张时规划 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 附录
|
||||
|
||||
### 9.1 租户状态机
|
||||
|
||||
```
|
||||
[新建中 Creating]
|
||||
↓ 成功
|
||||
[活跃 Active] ←──────────────────┐
|
||||
↓ 手动挂起 │ 到期自动恢复 / 手动恢复
|
||||
[已挂起 Suspended] ───────────────┘
|
||||
↓ 删除操作(软删除)
|
||||
[待清除 Pending Delete](冷静期 30 天)
|
||||
↓ 冷静期到期 / 硬删除
|
||||
[已删除 Deleted]
|
||||
```
|
||||
|
||||
### 9.2 管理员角色权限矩阵
|
||||
|
||||
| 操作 | Platform Admin(平台超级管理员) | 运营人员 | 只读审计员 |
|
||||
|------|-----------|---------|-----------|
|
||||
| 创建租户 | ✅ | ✅ | ❌ |
|
||||
| 挂起 / 恢复租户 | ✅ | ✅ | ❌ |
|
||||
| 软删除租户 | ✅ | ✅ | ❌ |
|
||||
| 硬删除租户 | ✅ | ❌ | ❌ |
|
||||
| 数据导出 | ✅ | ✅ | ❌ |
|
||||
| 手动触发备份 | ✅ | ✅ | ❌ |
|
||||
| 数据恢复 | ✅ | ❌ | ❌ |
|
||||
| 系统升级 | ✅ | ❌ | ❌ |
|
||||
| 系统回滚 | ✅ | ❌ | ❌ |
|
||||
| 查看版本总览 | ✅ | ✅ | ❌ |
|
||||
| 配置告警规则 | ✅ | ✅ | ❌ |
|
||||
| 查看审计日志 | ✅ | ✅ | ✅ |
|
||||
| 导出审计日志 | ✅ | ✅ | ✅ |
|
||||
| 管理员账号管理 | ✅ | ❌ | ❌ |
|
||||
| 强制登出管理员 | ✅ | ❌ | ❌ |
|
||||
| 配置 IP 白名单 | ✅ | ❌ | ❌ |
|
||||
|
||||
### 9.3 页面路由规划(管理控制台)
|
||||
|
||||
```
|
||||
/admin/ # 仪表盘
|
||||
/admin/tenants/ # 租户列表
|
||||
/admin/tenants/new/ # 新建租户
|
||||
/admin/tenants/{id}/ # 租户详情(信息)
|
||||
/admin/tenants/{id}/users/ # 租户用户管理
|
||||
/admin/tenants/{id}/plan/ # 套餐信息与升级
|
||||
/admin/tenants/{id}/monitoring/ # 监控数据
|
||||
/admin/tenants/{id}/backups/ # 备份记录
|
||||
/admin/tenants/{id}/history/ # 操作历史
|
||||
/admin/system/versions/ # 版本管理
|
||||
/admin/system/backups/ # 备份管理
|
||||
/admin/monitoring/ # 全局监控与告警
|
||||
/admin/audit-logs/ # 审计日志
|
||||
/admin/settings/admins/ # 管理员设置
|
||||
```
|
||||
Reference in New Issue
Block a user