feat: batch update - gift card breakdown spec, backend APIs, miniprogram pages, ETL finance recharge, docs & migrations
This commit is contained in:
532
docs/prd/Neo_Specs/NS4-tenant-admin-web.md
Normal file
532
docs/prd/Neo_Specs/NS4-tenant-admin-web.md
Normal file
@@ -0,0 +1,532 @@
|
||||
# NS4:租户管理后台 — tenant-admin-web
|
||||
|
||||
> 优先级:中(可与 NS1/NS2 并行,依赖 P1+P3)
|
||||
> 预估工作量:大
|
||||
> 前置条件:P1(数据库基础)、P3(用户认证体系)、admin-web-console 需求 11(租户管理员账号管理)
|
||||
> 参考基准:`docs/prd/specs/P10-tenant-admin-web.md`
|
||||
|
||||
---
|
||||
|
||||
## 一、背景与目标
|
||||
|
||||
当前系统缺少面向租户管理员的独立管理界面。用户审核、Excel 数据上传、维客线索管理等运营操作无法自助完成,依赖开发人员手动操作数据库。
|
||||
|
||||
本 SPEC 目标:构建独立的租户管理 Web 应用,提供:
|
||||
1. 用户审核与管理(申请审核、身份编辑、店铺归属、助教/员工绑定)
|
||||
2. Excel 数据上传(4 种模板:财务支出/团购收入/助教奖罚/充值业绩归属)
|
||||
3. 维客线索管理(查看、修改、删除、隐藏)
|
||||
|
||||
### 与现有系统的关系
|
||||
|
||||
| 系统 | 用途 | 用户 |
|
||||
|------|------|------|
|
||||
| `apps/admin-web/`(系统管理后台) | 平台级管理(Operator 操作) | 系统管理员 |
|
||||
| `apps/tenant-admin/`(本 SPEC) | 租户级管理 | 租户管理员 |
|
||||
| `apps/miniprogram/`(小程序) | C 端业务 | 助教/管理者 |
|
||||
|
||||
租户管理员账号由系统管理后台(`apps/admin-web/`)的 Operator 创建,租户管理员不可自行注册。
|
||||
|
||||
---
|
||||
|
||||
## 二、技术架构
|
||||
|
||||
### 2.1 前端
|
||||
|
||||
- 独立 Web 应用:React + Vite + Ant Design(与 `apps/admin-web/` 同技术栈)
|
||||
- 部署路径:`apps/tenant-admin/`
|
||||
- 独立登录入口,与系统管理后台完全隔离
|
||||
|
||||
```
|
||||
apps/tenant-admin/
|
||||
├── src/
|
||||
│ ├── pages/
|
||||
│ │ ├── Login/ # 登录页
|
||||
│ │ ├── UserApproval/ # 用户审核
|
||||
│ │ ├── UserManagement/ # 用户管理
|
||||
│ │ ├── ExcelUpload/ # Excel 上传(4 种模板)
|
||||
│ │ └── RetentionClues/ # 维客线索管理
|
||||
│ ├── components/
|
||||
│ │ ├── DiffTable/ # 冲突 diff 交互组件
|
||||
│ │ └── ClueEditor/ # 线索编辑组件
|
||||
│ ├── services/
|
||||
│ │ └── api.ts # API 调用封装
|
||||
│ ├── hooks/
|
||||
│ ├── utils/
|
||||
│ └── App.tsx
|
||||
├── package.json
|
||||
├── vite.config.ts
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
### 2.2 后端
|
||||
|
||||
复用 `apps/backend/` 的 FastAPI,新增租户管理路由模块:
|
||||
|
||||
```
|
||||
apps/backend/app/routers/
|
||||
├── tenant_auth.py 🆕 租户管理员登录/鉴权
|
||||
├── tenant_users.py 🆕 用户审核 + 用户管理
|
||||
├── tenant_excel.py 🆕 Excel 上传/校验/冲突处理
|
||||
└── tenant_clues.py 🆕 维客线索管理
|
||||
```
|
||||
|
||||
### 2.3 认证体系
|
||||
|
||||
- 独立凭据:用户名 + 密码(非微信登录)
|
||||
- JWT 签发:与小程序 JWT 独立(不同 issuer 或 audience)
|
||||
- 账号创建:由系统管理后台 Operator 创建,指定用户名、初始密码、所属租户、管辖 site_id 列表
|
||||
- 权限级别:
|
||||
- 租户级管理员:管辖该租户下所有店铺
|
||||
- 店铺级管理员:只能管理 Operator 分配的 site_id 列表内的店铺
|
||||
|
||||
### 2.4 数据隔离
|
||||
|
||||
- 所有查询附加 `site_id IN (管辖列表)` 条件
|
||||
- FDW 查询需 `SET LOCAL app.current_site_id`(单店铺场景)
|
||||
- 多店铺场景下,逐 site_id 查询后合并结果
|
||||
|
||||
---
|
||||
|
||||
## 三、功能详细设计
|
||||
|
||||
### 3.1 用户审核页面
|
||||
|
||||
#### 页面功能
|
||||
|
||||
- 申请列表:展示所有待审核/已审核的用户申请
|
||||
- 状态筛选:全部 / 待审核(pending) / 已通过(approved) / 已拒绝(rejected)
|
||||
- 关联建议:根据申请中的球房 ID + 手机号,同时在助教表和员工信息表中匹配
|
||||
- 审核操作:通过(分配身份+关联助教/员工)/ 拒绝(填写原因)
|
||||
|
||||
#### 关联匹配逻辑
|
||||
|
||||
```
|
||||
用户申请(球房ID + 手机号)
|
||||
→ site_code_mapping 查 site_id
|
||||
→ 并行匹配:
|
||||
├── fdw_etl.v_dim_assistant(phone 匹配,scd2_is_current=1)
|
||||
└── fdw_etl.v_dim_staff + v_dim_staff_ex(phone 匹配)
|
||||
→ 返回匹配建议列表(可能多条)
|
||||
→ 管理员选择关联目标
|
||||
```
|
||||
|
||||
#### 审核通过后操作
|
||||
|
||||
1. 更新 `auth.users.status = 'approved'`
|
||||
2. 分配角色(助教/管理者)→ 写入 `auth.user_roles`
|
||||
3. 关联助教 → 写入 `auth.user_assistant_binding`(含 staff_id)
|
||||
4. 分配 site_id → 更新 `auth.users.site_id`
|
||||
|
||||
#### 接口设计
|
||||
|
||||
| 接口 | 方法 | 路径 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 申请列表 | GET | `/api/tenant/applications` | 支持 status 筛选、分页 |
|
||||
| 关联建议 | GET | `/api/tenant/applications/{id}/match-suggestions` | 返回助教+员工匹配结果 |
|
||||
| 审核通过 | POST | `/api/tenant/applications/{id}/approve` | body: role, assistant_id, staff_id |
|
||||
| 审核拒绝 | POST | `/api/tenant/applications/{id}/reject` | body: reason |
|
||||
|
||||
### 3.2 用户管理页面
|
||||
|
||||
#### 页面功能
|
||||
|
||||
- 用户列表:展示已通过审核的用户(姓名、角色、关联助教、店铺、状态)
|
||||
- 身份编辑:修改角色(助教↔管理者)
|
||||
- 店铺归属:修改用户的 site_id
|
||||
- 关联助教/员工:修改绑定关系
|
||||
- 禁用/启用:冻结用户账号
|
||||
|
||||
#### 接口设计
|
||||
|
||||
| 接口 | 方法 | 路径 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 用户列表 | GET | `/api/tenant/users` | 支持角色筛选、搜索、分页 |
|
||||
| 编辑用户 | PATCH | `/api/tenant/users/{id}` | body: role, site_id, status |
|
||||
| 修改绑定 | PUT | `/api/tenant/users/{id}/binding` | body: assistant_id, staff_id |
|
||||
|
||||
### 3.3 Excel 上传
|
||||
|
||||
#### 4 种模板
|
||||
|
||||
##### 模板 1:财务支出(按月)
|
||||
|
||||
| 列名 | 类型 | 必填 | 校验规则 |
|
||||
|------|------|------|---------|
|
||||
| 月份 | YYYY-MM | 是 | 格式校验,不超过当前月 |
|
||||
| 支出类别 | 文本 | 是 | 枚举:房租/水电/物业/食品饮料进货/耗材/报销/固定人员工资/其他费用 |
|
||||
| 金额 | 数值(2) | 是 | > 0,精度 2 位小数 |
|
||||
| 备注 | 文本 | 否 | 最长 500 字符 |
|
||||
|
||||
主键:月份 + 支出类别
|
||||
写入目标:`dws.dws_finance_expense_summary`(通过后端 API 写入 ETL 库,或写入业务库 staging 表后由 ETL 同步)
|
||||
|
||||
##### 模板 2:团购平台收入(按月)
|
||||
|
||||
| 列名 | 类型 | 必填 | 校验规则 |
|
||||
|------|------|------|---------|
|
||||
| 月份 | YYYY-MM | 是 | 格式校验 |
|
||||
| 平台名称 | 文本 | 是 | 非空 |
|
||||
| 收入金额 | 数值(2) | 是 | > 0 |
|
||||
| 备注 | 文本 | 否 | 最长 500 字符 |
|
||||
|
||||
主键:月份 + 平台名称
|
||||
写入目标:`dws.dws_platform_settlement`(或业务库 staging 表)
|
||||
|
||||
##### 模板 3:助教奖罚(按月)
|
||||
|
||||
| 列名 | 类型 | 必填 | 校验规则 |
|
||||
|------|------|------|---------|
|
||||
| 月份 | YYYY-MM | 是 | 格式校验 |
|
||||
| 助教姓名 | 文本 | 是 | 非空 |
|
||||
| 助教编号 | 文本 | 是 | 非空 |
|
||||
| 类型 | 文本 | 是 | 枚举:扣款/奖金 |
|
||||
| 金额 | 数值(2) | 是 | > 0 |
|
||||
| 原因 | 文本 | 是 | 非空,最长 200 字符 |
|
||||
|
||||
主键:月份 + 助教姓名 + 助教编号 + 类型 + 原因(同一助教同月可多笔)
|
||||
写入目标:`biz.salary_adjustments`
|
||||
|
||||
##### 模板 4:充值业绩归属(按月)
|
||||
|
||||
| 列名 | 类型 | 必填 | 校验规则 |
|
||||
|------|------|------|---------|
|
||||
| 充值日期 | YYYY-MM-DD | 是 | 格式校验 |
|
||||
| 会员名称 | 文本 | 是 | 非空 |
|
||||
| 充值金额 | 数值(2) | 是 | > 0 |
|
||||
| 归属助教 | 文本 | 是 | 非空 |
|
||||
| 奖励金额 | 数值(2) | 是 | ≥ 0 |
|
||||
|
||||
主键:充值日期 + 会员名称 + 归属助教
|
||||
写入目标:`dws.dws_assistant_recharge_commission`(或业务库 staging 表)
|
||||
|
||||
#### 人员匹配校验(模板 3/4)
|
||||
|
||||
上传助教奖罚和充值业绩归属时,需校验助教姓名+编号是否存在:
|
||||
|
||||
```
|
||||
助教姓名 + 助教编号
|
||||
→ fdw_etl.v_dim_assistant(nickname + assistant_number 匹配,scd2_is_current=1)
|
||||
→ 如不匹配,尝试 fdw_etl.v_dim_staff + v_dim_staff_ex(name + staff_number 匹配)
|
||||
→ 匹配失败:标记为校验警告(不阻断上传,但提示管理员确认)
|
||||
```
|
||||
|
||||
#### 冲突处理流程
|
||||
|
||||
```
|
||||
上传 Excel
|
||||
→ 后端解析 + 格式校验
|
||||
→ 返回校验结果:
|
||||
├── 格式错误行 → 前端标红,要求修正后重新上传
|
||||
├── 无冲突行 → 标记为"待写入"
|
||||
└── 冲突行(主键已存在)→ 返回 diff 数据(旧值 vs 新值)
|
||||
→ 前端展示 diff 交互表格:
|
||||
- 每行显示:字段名 | 旧值 | 新值 | 操作(替换/保留)
|
||||
- 支持"全部替换"/"全部保留"快捷操作
|
||||
→ 用户确认后提交
|
||||
→ 后端按选择写入
|
||||
```
|
||||
|
||||
#### 接口设计
|
||||
|
||||
| 接口 | 方法 | 路径 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 上传解析 | POST | `/api/tenant/excel/upload` | multipart/form-data,返回校验结果+冲突列表 |
|
||||
| 确认写入 | POST | `/api/tenant/excel/confirm` | body: upload_id, resolutions[] |
|
||||
| 上传记录 | GET | `/api/tenant/excel/logs` | 历史上传记录列表 |
|
||||
| 模板下载 | GET | `/api/tenant/excel/template/{type}` | 下载空白模板 |
|
||||
|
||||
### 3.4 维客线索管理
|
||||
|
||||
#### 页面功能
|
||||
|
||||
- 客户搜索:按客户姓名/手机号搜索(姓名从 dim_member.nickname,手机从 dim_member.mobile)
|
||||
- 门店筛选:按管辖 site_id 筛选
|
||||
- 线索列表:展示该客户的全部维客线索
|
||||
- 标签(大类枚举:客户基础/消费习惯/玩法偏好/促销偏好/社交关系/重要反馈)
|
||||
- 摘要(含 Emoji 前缀)
|
||||
- 详情
|
||||
- 提供人(recorded_by_name)
|
||||
- 来源(manual / ai_consumption / ai_note)
|
||||
- 记录时间
|
||||
- 隐藏状态
|
||||
- 操作:
|
||||
- 修改:编辑标签、摘要、详情
|
||||
- 删除:二次确认后物理删除
|
||||
- 隐藏/显示:切换 `is_hidden` 状态
|
||||
|
||||
#### 数据源
|
||||
|
||||
- `zqyy_app.public.member_retention_clue`(线索数据)
|
||||
- `fdw_etl.v_dim_member`(客户信息:nickname、mobile,通过 member_id 关联)
|
||||
|
||||
> ⚠️ 会员字段断档(DQ-6):客户姓名/手机必须从 dim_member 获取,不可使用结算单上的冗余字段
|
||||
|
||||
#### 接口设计
|
||||
|
||||
| 接口 | 方法 | 路径 | 说明 |
|
||||
|------|------|------|------|
|
||||
| 客户搜索 | GET | `/api/tenant/customers/search` | query: keyword, site_id |
|
||||
| 线索列表 | GET | `/api/tenant/customers/{member_id}/clues` | 该客户全部线索 |
|
||||
| 修改线索 | PATCH | `/api/tenant/clues/{id}` | body: category, summary, detail |
|
||||
| 删除线索 | DELETE | `/api/tenant/clues/{id}` | 二次确认后物理删除 |
|
||||
| 隐藏/显示 | PATCH | `/api/tenant/clues/{id}/visibility` | body: is_hidden |
|
||||
|
||||
---
|
||||
|
||||
## 四、数据库审查与新增表
|
||||
|
||||
### 4.1 现有表满足度
|
||||
|
||||
| 功能 | 现有表 | 是否满足 | 缺口 |
|
||||
|------|--------|---------|------|
|
||||
| 用户审核 | auth.users, auth.user_applications | ✅ 满足 | 无 |
|
||||
| 用户管理 | auth.users, auth.user_roles, auth.user_assistant_binding | ✅ 满足 | 无 |
|
||||
| 维客线索 | public.member_retention_clue | ⚠️ 部分 | 缺 is_hidden 字段 |
|
||||
| 助教奖罚 | — | ❌ 不满足 | 需新建 biz.salary_adjustments |
|
||||
| 上传记录 | — | ❌ 不满足 | 需新建 biz.excel_upload_log |
|
||||
| 财务支出/团购收入/充值归属 | DWS 表 | ⚠️ 待定 | 可能需要 staging 表 |
|
||||
|
||||
### 4.2 需新建的表
|
||||
|
||||
#### 表 1:`biz.salary_adjustments`(助教奖罚明细)
|
||||
|
||||
```sql
|
||||
CREATE TABLE biz.salary_adjustments (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
site_id BIGINT NOT NULL,
|
||||
assistant_id BIGINT, -- 匹配到的助教 ID(可空,匹配失败时为 NULL)
|
||||
assistant_name VARCHAR(100) NOT NULL,
|
||||
assistant_number VARCHAR(50) NOT NULL,
|
||||
salary_month VARCHAR(7) NOT NULL, -- YYYY-MM
|
||||
adjustment_type VARCHAR(20) NOT NULL CHECK (adjustment_type IN ('deduction', 'bonus')),
|
||||
amount NUMERIC(12,2) NOT NULL CHECK (amount > 0),
|
||||
reason VARCHAR(200) NOT NULL,
|
||||
upload_batch_id BIGINT REFERENCES biz.excel_upload_log(id),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
created_by BIGINT -- 上传人(租户管理员 ID)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_salary_adj_site_month ON biz.salary_adjustments(site_id, salary_month);
|
||||
CREATE INDEX idx_salary_adj_assistant ON biz.salary_adjustments(assistant_id, salary_month);
|
||||
```
|
||||
|
||||
#### 表 2:`biz.excel_upload_log`(Excel 上传记录)
|
||||
|
||||
```sql
|
||||
CREATE TABLE biz.excel_upload_log (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
site_id BIGINT NOT NULL,
|
||||
upload_type VARCHAR(30) NOT NULL CHECK (upload_type IN (
|
||||
'expense', 'platform_income', 'salary_adj', 'recharge_commission'
|
||||
)),
|
||||
file_name VARCHAR(255) NOT NULL,
|
||||
uploaded_by BIGINT NOT NULL, -- 租户管理员 ID
|
||||
row_count INTEGER NOT NULL DEFAULT 0,
|
||||
conflict_count INTEGER NOT NULL DEFAULT 0,
|
||||
resolved_count INTEGER NOT NULL DEFAULT 0,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'pending' CHECK (status IN (
|
||||
'pending', 'confirmed', 'failed'
|
||||
)),
|
||||
error_detail JSONB, -- 校验错误详情
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
confirmed_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE INDEX idx_excel_log_site ON biz.excel_upload_log(site_id, created_at DESC);
|
||||
```
|
||||
|
||||
### 4.3 需变更的表
|
||||
|
||||
#### `public.member_retention_clue` — 新增字段
|
||||
|
||||
```sql
|
||||
ALTER TABLE public.member_retention_clue
|
||||
ADD COLUMN is_hidden BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
COMMENT ON COLUMN public.member_retention_clue.is_hidden
|
||||
IS '是否隐藏(true=管理后台保留但小程序不展示)';
|
||||
```
|
||||
|
||||
> 小程序端查询线索时需增加 `WHERE is_hidden = false` 条件
|
||||
|
||||
#### `public.member_retention_clue` — 确认 source 字段
|
||||
|
||||
P10 spec 中提到需新增 `source` 字段,需确认该字段是否已在 P4/P5 阶段建立。如未建立:
|
||||
|
||||
```sql
|
||||
ALTER TABLE public.member_retention_clue
|
||||
ADD COLUMN source VARCHAR(20) NOT NULL DEFAULT 'manual'
|
||||
CHECK (source IN ('manual', 'ai_consumption', 'ai_note'));
|
||||
|
||||
COMMENT ON COLUMN public.member_retention_clue.source
|
||||
IS '线索来源:manual=人工录入, ai_consumption=应用3消费分析, ai_note=应用6备注分析';
|
||||
```
|
||||
|
||||
### 4.4 Excel 写入目标表的 staging 策略
|
||||
|
||||
财务支出、团购收入、充值业绩归属三种模板的数据最终需要进入 DWS 层。有两种策略:
|
||||
|
||||
**方案 A:直接写入 DWS 表**(通过后端 API 直连 ETL 库写入)
|
||||
- 优点:数据即时可用
|
||||
- 缺点:绕过 ETL 流程,数据一致性风险
|
||||
|
||||
**方案 B:写入业务库 staging 表,ETL 定时同步**
|
||||
- 优点:数据经过 ETL 标准流程,一致性有保障
|
||||
- 缺点:数据有延迟(取决于 ETL 调度频率)
|
||||
|
||||
建议采用方案 B,需新建 3 张 staging 表:
|
||||
|
||||
```sql
|
||||
-- biz.stg_finance_expense(财务支出 staging)
|
||||
CREATE TABLE biz.stg_finance_expense (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
site_id BIGINT NOT NULL,
|
||||
expense_month VARCHAR(7) NOT NULL,
|
||||
category VARCHAR(50) NOT NULL,
|
||||
amount NUMERIC(12,2) NOT NULL,
|
||||
remark TEXT,
|
||||
upload_batch_id BIGINT REFERENCES biz.excel_upload_log(id),
|
||||
synced_at TIMESTAMPTZ, -- ETL 同步时间(NULL=未同步)
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- biz.stg_platform_income(团购收入 staging)
|
||||
CREATE TABLE biz.stg_platform_income (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
site_id BIGINT NOT NULL,
|
||||
income_month VARCHAR(7) NOT NULL,
|
||||
platform_name VARCHAR(100) NOT NULL,
|
||||
amount NUMERIC(12,2) NOT NULL,
|
||||
remark TEXT,
|
||||
upload_batch_id BIGINT REFERENCES biz.excel_upload_log(id),
|
||||
synced_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- biz.stg_recharge_commission(充值业绩归属 staging)
|
||||
CREATE TABLE biz.stg_recharge_commission (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
site_id BIGINT NOT NULL,
|
||||
recharge_date DATE NOT NULL,
|
||||
member_name VARCHAR(100) NOT NULL,
|
||||
recharge_amount NUMERIC(12,2) NOT NULL,
|
||||
assigned_assistant VARCHAR(100) NOT NULL,
|
||||
reward_amount NUMERIC(12,2) NOT NULL,
|
||||
upload_batch_id BIGINT REFERENCES biz.excel_upload_log(id),
|
||||
synced_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、租户管理员账号体系
|
||||
|
||||
### 5.1 账号存储
|
||||
|
||||
租户管理员账号存储在 `auth.tenant_admins` 表(需新建):
|
||||
|
||||
```sql
|
||||
CREATE TABLE auth.tenant_admins (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
username VARCHAR(50) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
display_name VARCHAR(100),
|
||||
tenant_id BIGINT NOT NULL, -- 所属租户
|
||||
managed_site_ids BIGINT[] NOT NULL, -- 管辖的 site_id 列表
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
created_by BIGINT, -- 创建该账号的 Operator ID
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
last_login_at TIMESTAMPTZ
|
||||
);
|
||||
|
||||
CREATE INDEX idx_tenant_admin_tenant ON auth.tenant_admins(tenant_id);
|
||||
```
|
||||
|
||||
### 5.2 与小程序用户体系的隔离
|
||||
|
||||
- 租户管理员使用 `auth.tenant_admins` 表,小程序用户使用 `auth.users` 表
|
||||
- JWT 签发时使用不同的 `aud`(audience)字段区分
|
||||
- 后端路由通过不同的认证依赖注入区分(`require_tenant_admin()` vs `require_approved()`)
|
||||
|
||||
---
|
||||
|
||||
## 六、参考文档
|
||||
|
||||
| 文档 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| P10 原始 spec | `docs/prd/specs/P10-tenant-admin-web.md` | 需求定义基准 |
|
||||
| admin-web 现有代码 | `apps/admin-web/` | 技术栈参考(React + Vite + Ant Design) |
|
||||
| BD 手册-认证表 | `docs/database/BD_Manual_auth_tables.md` | auth schema 表结构 |
|
||||
| BD 手册-业务表 | `docs/database/BD_Manual_biz_tables.md` | biz schema 表结构 |
|
||||
| 权限矩阵 | `docs/permission_matrix/` | 角色-权限映射参考 |
|
||||
| DWD-DOC 标杆 | `docs/reports/DWD-DOC/` | 金额口径权威参考 |
|
||||
| 数据依赖矩阵 | `docs/prd/specs/00-数据依赖矩阵.md` | 租户管理后台数据源映射 |
|
||||
| member_retention_clue DDL | `db/zqyy_app/` | 维客线索表结构 |
|
||||
|
||||
---
|
||||
|
||||
## 七、预审查清单(SPEC 启动前确认)
|
||||
|
||||
### 7.1 账号与认证
|
||||
|
||||
1. **租户管理员账号模型**:是否需要独立的 `auth.tenant_admins` 表?还是复用 `auth.users` 表增加 `user_type` 字段区分?
|
||||
2. **密码策略**:初始密码是否需要强制修改?密码复杂度要求?是否需要密码过期机制?
|
||||
3. **多租户隔离**:一个管理员是否可以管辖多个租户?还是严格一对一?
|
||||
4. **会话管理**:JWT 过期时间?是否需要 refresh token?是否支持多设备同时登录?
|
||||
|
||||
### 7.2 用户审核
|
||||
|
||||
5. **关联匹配优先级**:助教表和员工信息表同时匹配到时,优先展示哪个?是否需要合并展示?
|
||||
6. **审核拒绝后**:用户是否可以重新申请?重新申请是新建记录还是更新原记录?
|
||||
7. **批量审核**:是否需要支持批量通过/拒绝?
|
||||
8. **审核通知**:审核结果是否需要通知用户(小程序消息/微信模板消息)?
|
||||
|
||||
### 7.3 Excel 上传
|
||||
|
||||
9. **写入策略**:财务支出/团购收入/充值归属是直接写入 DWS 表(方案 A)还是写入 staging 表由 ETL 同步(方案 B)?
|
||||
10. **文件大小限制**:单次上传的 Excel 文件大小上限?行数上限?
|
||||
11. **历史数据**:是否允许上传历史月份的数据?是否有时间范围限制?
|
||||
12. **模板版本**:Excel 模板是否需要版本管理?表头变更时如何兼容旧模板?
|
||||
13. **助教匹配失败处理**:模板 3/4 中助教姓名+编号匹配失败时,是阻断上传还是允许上传但标记警告?
|
||||
|
||||
### 7.4 维客线索
|
||||
|
||||
14. **隐藏 vs 删除**:隐藏的线索是否可以恢复显示?删除是否需要软删除(保留记录但标记删除)?
|
||||
15. **AI 线索保护**:AI 生成的线索(source=ai_consumption/ai_note)是否允许管理员修改/删除?修改后 source 是否变更为 manual?
|
||||
16. **线索审计**:线索的修改/删除操作是否需要记录操作日志(谁在什么时间做了什么操作)?
|
||||
17. **批量操作**:是否需要支持批量隐藏/删除线索?
|
||||
|
||||
### 7.5 部署与运维
|
||||
|
||||
18. **部署方式**:租户管理后台是独立部署还是与系统管理后台共享服务器?域名/路径如何规划?
|
||||
19. **前端构建**:是否与 admin-web 共享 pnpm workspace?还是完全独立的 package.json?
|
||||
20. **监控**:是否需要独立的访问日志和错误监控?
|
||||
|
||||
---
|
||||
|
||||
## 八、任务清单(草案,SPEC 细化后调整)
|
||||
|
||||
### Batch A:基础设施
|
||||
- [ ] T1:创建 `apps/tenant-admin/` 项目骨架(React + Vite + Ant Design)
|
||||
- [ ] T2:创建 `auth.tenant_admins` 表 + DDL 迁移脚本
|
||||
- [ ] T3:实现租户管理员登录 API(`tenant_auth.py`:登录/JWT 签发/鉴权中间件)
|
||||
- [ ] T4:创建 `biz.salary_adjustments` + `biz.excel_upload_log` 表 + DDL 迁移脚本
|
||||
|
||||
### Batch B:用户审核与管理
|
||||
- [ ] T5:实现用户审核后端 API(申请列表/关联建议/审核通过/审核拒绝)
|
||||
- [ ] T6:实现用户审核前端页面(申请列表 + 状态筛选 + 关联建议展示 + 审核操作)
|
||||
- [ ] T7:实现用户管理后端 API(用户列表/编辑/绑定修改)
|
||||
- [ ] T8:实现用户管理前端页面(用户列表 + 身份编辑 + 店铺归属)
|
||||
|
||||
### Batch C:Excel 上传
|
||||
- [ ] T9:实现 Excel 解析+校验后端(4 种模板的格式校验 + 人员匹配校验)
|
||||
- [ ] T10:实现冲突检测后端(主键匹配 + diff 数据生成)
|
||||
- [ ] T11:实现 Excel 上传前端(模板下载 + 上传 + 校验结果展示 + diff 交互 + 确认)
|
||||
- [ ] T12:创建 staging 表(如采用方案 B)+ 写入逻辑
|
||||
|
||||
### Batch D:维客线索管理
|
||||
- [ ] T13:`member_retention_clue` 新增 `is_hidden` 字段 + DDL 迁移
|
||||
- [ ] T14:实现维客线索后端 API(客户搜索/线索列表/修改/删除/隐藏)
|
||||
- [ ] T15:实现维客线索前端页面(客户搜索 + 线索列表 + 编辑/删除/隐藏操作)
|
||||
- [ ] T16:小程序端线索查询增加 `WHERE is_hidden = false` 条件
|
||||
Reference in New Issue
Block a user