diff --git a/docs/租户配置与用户管理指南.md b/docs/租户配置与用户管理指南.md new file mode 100644 index 0000000..8ace73d --- /dev/null +++ b/docs/租户配置与用户管理指南.md @@ -0,0 +1,739 @@ +# 租户配置与用户管理指南 + +## 概述 + +系统采用多租户架构,平台管理员可创建租户(连锁品牌),每个租户有独立的业务数据库。租户管理员(hq)可在租户内创建区域经理、店长等角色。 + +### 角色体系 + +| 角色 | role 值 | 说明 | 数据范围 | +|------|---------|------|----------| +| 平台管理员 | `platform_admin` | SaaS 平台运维,管理所有租户 | 全平台 | +| 总部管理员 | `hq` | 租户内最高权限,管理本租户用户 | 本租户全部数据 | +| 商品部 | `dept` | 商品/供应链相关功能 | 本租户全部数据 | +| 区域经理 | `regional` | 管辖指定门店,看区域汇总 | `region` 字段指定的门店 | +| 店长 | `store` | 管理指定门店 | `store_code` 字段指定的门店 | + +### 数据库结构 + +- **sbrain_admin**(平台管理库,服务器端口 5432):存放 `tenant_configs`(租户配置)、`tenant_users`(租户用户)和 `platform_admins`(平台管理员) +- **bill_query**(业务数据库,客户本机端口 5432):存放各租户的业务数据,通过 FRP 隧道映射到服务器的 16xxx 端口(现有租户用 15432,新租户从 16001 起) + +### 架构示意 + +``` +租户A用户 ─┐ +租户B用户 ─┤→ Nginx(服务器) → 后端(服务器:9333) → 识别租户 → 连对应frp端口 → 客户本机PostgreSQL +租户C用户 ─┘ + +浏览器 → https://dm.all8ai.top + → Nginx 反向代理 /api/ → 127.0.0.1:9333 (服务器后端) + → 后端解析 JWT 获取 tenant_id + → 查 tenant_configs 表获取该租户的 frp 端口 + → 连接 127.0.0.1:16xxx (frp 隧道) + → frp 转发到客户本机 127.0.0.1:5432 (PostgreSQL) + → 返回数据 +``` + +### 组件部署位置 + +| 组件 | 位置 | 说明 | +|------|------|------| +| 前端(静态文件) | 服务器 | Nginx 托管,统一部署 | +| 后端(Node.js) | 服务器 | pm2 管理,一套代码服务所有租户 | +| 服务器主库(PostgreSQL) | 服务器 5432 端口 | 仅存 `tenant_configs`、`tenant_users`、`platform_admins`,不存业务数据 | +| 业务数据库(PostgreSQL) | 客户本机 5432 端口 | 每个租户自己的数据库,数据完全在客户侧 | +| frps(frp服务端) | 服务器 7000 端口 | 接收各租户 frp 客户端连接 | +| frpc(frp客户端) | 客户本机 | 每个租户运行自己的 frpc,暴露本机 PostgreSQL | + +--- + +## 〇、新租户接入全流程 + +接入一个新租户需要完成以下 4 个阶段: + +``` +阶段1:客户本机准备 PostgreSQL 数据库 +阶段2:配置 frp 隧道(客户本机 frpc + 服务器 frps 端口分配) +阶段3:服务器后台创建租户配置并激活 +阶段4:创建用户账号(hq → regional → store) +``` + +### 阶段1:客户本机准备数据库 + +#### 1.1 安装 PostgreSQL + +```bash +# macOS (Homebrew) +brew install postgresql@15 +brew services start postgresql@15 + +# Ubuntu/Debian +sudo apt install postgresql postgresql-contrib +sudo systemctl start postgresql +``` + +#### 1.2 创建数据库和用户 + +```bash +# 进入 PostgreSQL +psql postgres + +# 创建数据库用户(如不需要密码,使用 trust 认证) +CREATE USER freedak SUPERUSER; + +# 创建业务数据库 +CREATE DATABASE bill_query OWNER freedak; + +# 退出 +\q +``` + +#### 1.3 导入业务数据 + +```bash +# 方式1:从备份文件恢复 +pg_restore -U freedak -d bill_query -1 /path/to/backup.dump + +# 方式2:从 SQL 文件导入 +psql -U freedak -d bill_query -f /path/to/init_data.sql + +# 验证数据 +psql -U freedak -d bill_query -c "SELECT count(*) FROM analytics.dim_store;" +``` + +#### 1.4 配置 PostgreSQL 允许本地连接 + +确保 `postgresql.conf` 中: + +```conf +listen_addresses = 'localhost' +port = 5432 +``` + +确保 `pg_hba.conf` 中允许本地 trust 连接(如使用密码则改为 md5/scram-sha-256): + +```conf +# TYPE DATABASE USER ADDRESS METHOD +local all all trust +host all all 127.0.0.1/32 trust +``` + +修改后重启 PostgreSQL: + +```bash +# macOS +brew services restart postgresql@15 + +# Ubuntu +sudo systemctl restart postgresql +``` + +### 阶段2:配置 frp 隧道 + +每个租户需要一条独立的 frp 隧道,将客户本机的 PostgreSQL 5432 端口映射到服务器的一个远程端口。 + +#### 2.1 服务器端 frps 配置 + +服务器上已运行 frps,配置文件位于 `/etc/frp/frps.toml`: + +```toml +bindAddr = "0.0.0.0" +bindPort = 7000 +auth.token = "frp_gitea_2026" +``` + +**无需修改**,frps 会自动接受来自 frpc 的连接。只需为每个租户分配一个不冲突的远程端口。 + +#### 2.2 分配远程端口 + +端口分配规则: + +| 租户 | tenant_id | 远程端口 | 用途 | +|------|-----------|----------|------| +| 西部马华 | tenant_a | 15432 | 已占用 | +| 新租户B | tenant_b | 16001 | 新分配 | +| 新租户C | tenant_c | 16002 | 新分配 | +| ... | ... | ... | 递增 | + +> **注意**:端口 15432 已被现有租户使用。新租户从 16001 开始分配。 + +#### 2.3 客户本机安装 frpc + +```bash +# macOS +brew install frp + +# 或手动下载 +# https://github.com/fatedier/frp/releases +# 下载对应平台的 frp,解压后取 frpc 可执行文件 +``` + +#### 2.4 客户本机配置 frpc + +创建配置文件 `/etc/frp/frpc.toml`(或 `~/.frp/frpc.toml`): + +```toml +serverAddr = "dm.all8ai.top" +serverPort = 7000 +auth.token = "frp_gitea_2026" +loginFailExit = false + +[[proxies]] +name = "tenant_b-db" +type = "tcp" +localIP = "127.0.0.1" +localPort = 5432 +remotePort = 16001 +``` + +> - `name`:必须唯一,建议用 `租户ID-db` 格式 +> - `remotePort`:使用分配的远程端口(如 16001) +> - `loginFailExit = false`:断线自动重连 + +#### 2.5 启动 frpc + +```bash +# 前台运行(测试用) +frpc -c /etc/frp/frpc.toml + +# 后台运行(生产用) +nohup frpc -c /etc/frp/frpc.toml > /var/log/frpc.log 2>&1 & + +# macOS 可用 brew services +brew services start frp +``` + +#### 2.6 验证隧道连通 + +在服务器上测试远程端口是否可达: + +```bash +# 在服务器上执行 +ssh ubuntu@152.136.182.184 "ss -tlnp | grep 16001" +# 应看到 LISTEN 状态 + +# 测试数据库连接 +ssh ubuntu@152.136.182.184 "psql -h 127.0.0.1 -p 16001 -U freedak -d bill_query -c 'SELECT 1;'" +# 应返回 1 +``` + +### 阶段3:服务器后台创建租户配置 + +隧道连通后,在系统中注册租户。 + +#### 3.1 平台管理员登录 + +- **入口**:https://dm.all8ai.top/login +- **用户名**:`平台管理员` +- **密码**:初始密码见部署配置 +- **登录后**:自动跳转到「租户管理」页面 + +#### 3.2 创建租户 + +在「租户管理」页面点击「新建租户」,填写以下信息: + +| 字段 | 说明 | 示例 | +|------|------|------| +| tenant_id | 租户唯一标识(英文,不可改) | `tenant_b` | +| tenant_name | 租户显示名称 | `B品牌连锁` | +| db_host | 业务数据库地址(固定) | `127.0.0.1` | +| db_port | frp 远程端口 | `16001` | +| db_name | 业务数据库名(固定) | `bill_query` | +| db_user | 数据库用户 | `freedak` | +| db_password | 数据库密码(空则不传) | (留空) | +| frp_port | FRP 隧道端口(同 db_port) | `16001` | + +> **关键**:`db_port` 和 `frp_port` 必须填 frp 分配的远程端口(如 16001),不是客户本机的 5432。 + +#### 3.3 激活租户 + +创建后默认状态为 `inactive`,需手动改为 `active`。 + +#### API 方式(阶段3完整示例) + +```bash +# 平台管理员登录获取 token +ADMIN_TOKEN=$(curl -s -X POST http://localhost:9333/api/admin/login \ + -H 'Content-Type: application/json' \ + -d '{"username":"平台管理员","password":"xxx"}' | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['token'])") + +# 创建租户 +curl -s -X POST http://localhost:9333/api/admin/tenants \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "tenant_id": "tenant_b", + "tenant_name": "B品牌连锁", + "db_host": "127.0.0.1", + "db_port": 16001, + "db_name": "bill_query", + "db_user": "freedak", + "db_password": "", + "frp_port": 16001 + }' + +# 激活租户 +curl -s -X PUT http://localhost:9333/api/admin/tenants/tenant_b \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"status": "active"}' + +# 验证数据库连接 +curl -s http://localhost:9333/api/admin/tenants/tenant_b/status \ + -H "Authorization: Bearer $ADMIN_TOKEN" +# 应返回 {"success":true,"data":{"connected":true}} +``` + +### 阶段4:创建用户账号 + +租户激活后,创建用户账号。详见下方「一、平台管理员操作」和「二、租户管理员操作」。 + +--- + +## 一、平台管理员操作 + +### 1.1 登录 + +- **入口**:https://dm.all8ai.top/login +- **用户名**:`平台管理员` +- **密码**:初始密码见部署配置 +- **登录后**:自动跳转到「租户管理」页面 + +### 1.2 创建新租户 + +> **前置条件**:客户本机已完成数据库准备和 frp 隧道配置(见「〇、新租户接入全流程」阶段1和阶段2),服务器上对应端口已可连通。 + +在「租户管理」页面点击「新建租户」,填写以下信息: + +| 字段 | 说明 | 示例 | +|------|------|------| +| tenant_id | 租户唯一标识(英文,不可改) | `tenant_b` | +| tenant_name | 租户显示名称 | `B品牌连锁` | +| db_host | 业务数据库地址(固定) | `127.0.0.1` | +| db_port | frp 远程端口(见阶段2分配) | `16001` | +| db_name | 业务数据库名(固定) | `bill_query` | +| db_user | 数据库用户 | `freedak` | +| db_password | 数据库密码(空则不传) | (留空) | +| frp_port | FRP 隧道端口(同 db_port) | `16001` | + +> **关键**:`db_port` 和 `frp_port` 必须填 frp 分配的远程端口(如 16001),不是客户本机的 5432。 + +**创建后默认状态为 `inactive`(未激活),需手动激活为 `active`。** + +#### API 方式 + +```bash +# 平台管理员登录获取 token +ADMIN_TOKEN=$(curl -s -X POST http://localhost:9333/api/admin/login \ + -H 'Content-Type: application/json' \ + -d '{"username":"平台管理员","password":"xxx"}' | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['token'])") + +# 创建租户 +curl -s -X POST http://localhost:9333/api/admin/tenants \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "tenant_id": "tenant_b", + "tenant_name": "B品牌连锁", + "db_host": "127.0.0.1", + "db_port": 16001, + "db_name": "bill_query", + "db_user": "freedak", + "db_password": "", + "frp_port": 16001 + }' + +# 激活租户 +curl -s -X PUT http://localhost:9333/api/admin/tenants/tenant_b \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"status": "active"}' + +# 验证数据库连接 +curl -s http://localhost:9333/api/admin/tenants/tenant_b/status \ + -H "Authorization: Bearer $ADMIN_TOKEN" +# 应返回 {"success":true,"data":{"connected":true}} +``` + +### 1.3 为租户创建总部管理员(hq) + +平台管理员为租户创建第一个 hq 用户,后续用户由 hq 自行管理: + +#### 界面操作 + +在「租户管理」页面 → 点击租户 → 「用户」标签 → 「添加用户」 + +#### API 方式 + +```bash +curl -s -X POST http://localhost:9333/api/admin/tenants/tenant_b/users \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "username": "brand_b_admin", + "password": "123", + "role": "hq", + "name": "B品牌管理员" + }' +``` + +> **注意**:平台管理员创建用户时不包含 `store_code`/`region`/`dept` 字段。如需设置,由租户管理员(hq)登录后通过用户管理页面编辑。 + +--- + +## 二、租户管理员(hq)操作 + +### 2.1 登录 + +- **入口**:https://dm.all8ai.top/login +- **用户名**:由平台管理员创建的 hq 账号 +- **登录后**:自动跳转到「总部驾驶舱」 + +### 2.2 用户管理 + +进入「系统管理」→「用户管理」页面,可执行以下操作: + +- **添加用户**:创建区域经理、店长、商品部账号 +- **编辑关联**:修改用户关联的门店/区域 +- **修改密码**:重置用户密码 +- **删除用户**:移除用户账号 + +### 2.3 创建区域经理(regional) + +1. 点击「添加用户」 +2. 填写信息: + - **用户名**:如 `haidian_manager` + - **密码**:如 `123` + - **角色**:选择「区域经理」 + - **姓名**:如 `海淀区区域经理` +3. **管辖门店**:在门店列表中勾选该区域经理管辖的门店(多选) + - `region` 字段存储的是**逗号分隔的门店编码**,如 `0016,0018,0020,...` + - 可通过搜索框按门店名称或区域筛选 +4. 点击「添加」 + +#### API 方式 + +```bash +# hq 登录获取 token +HQ_TOKEN=$(curl -s -X POST http://localhost:9333/api/auth/login \ + -H 'Content-Type: application/json' \ + -d '{"username":"brand_b_admin","password":"123"}' | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['token'])") + +# 创建区域经理(region 字段填逗号分隔的门店编码) +curl -s -X POST http://localhost:9333/api/admin/tenant/users \ + -H "Authorization: Bearer $HQ_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "username": "haidian_manager", + "password": "123", + "role": "regional", + "name": "海淀区区域经理", + "region": "0016,0018,0020,0022,0024,0025,0028,0029,0032,0049,0054,0059,..." + }' +``` + +### 2.4 创建店长(store) + +1. 点击「添加用户」 +2. 填写信息: + - **用户名**:如 `wanquanhe_manager` + - **密码**:如 `123` + - **角色**:选择「店长」 + - **姓名**:如 `万泉河店长` +3. **所属门店**:在门店列表中勾选该店长管理的门店(可多选) + - `store_code` 字段存储逗号分隔的门店编码,如 `0016` +4. 点击「添加」 + +#### API 方式 + +```bash +curl -s -X POST http://localhost:9333/api/admin/tenant/users \ + -H "Authorization: Bearer $HQ_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "username": "wanquanhe_manager", + "password": "123", + "role": "store", + "name": "万泉河店长", + "store_code": "0016" + }' +``` + +### 2.5 创建商品部(dept) + +1. 点击「添加用户」 +2. 填写信息: + - **用户名**:如 `product_dept` + - **密码**:如 `123` + - **角色**:选择「商品部」 + - **姓名**:如 `商品部` +3. **部门**:填写部门名称,如 `商品部` +4. 点击「添加」 + +#### API 方式 + +```bash +curl -s -X POST http://localhost:9333/api/admin/tenant/users \ + -H "Authorization: Bearer $HQ_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "username": "product_dept", + "password": "123", + "role": "dept", + "name": "商品部", + "dept": "商品部" + }' +``` + +### 2.6 编辑用户关联门店 + +创建用户后如需修改关联门店: + +1. 在用户列表中点击「编辑」图标 +2. 重新勾选/取消勾选门店 +3. 点击「保存」 + +#### API 方式 + +```bash +# 修改用户关联的门店编码 +curl -s -X PUT http://localhost:9333/api/admin/tenant/users/5 \ + -H "Authorization: Bearer $HQ_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "store_code": "0016,0018", + "region": "", + "dept": "" + }' +``` + +### 2.7 修改用户密码 + +1. 在用户列表中点击「钥匙」图标 +2. 输入新密码 +3. 点击「确认修改」 + +#### API 方式 + +```bash +curl -s -X PUT http://localhost:9333/api/admin/tenant/users/5/password \ + -H "Authorization: Bearer $HQ_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"password": "newpass"}' +``` + +--- + +## 三、数据范围机制 + +### 3.1 字段说明 + +| 角色 | 字段 | 存储内容 | 示例 | +|------|------|----------|------| +| hq / dept | (无) | 不做数据过滤 | - | +| regional | `region` | 逗号分隔的门店编码 | `0016,0018,0020,...` | +| store | `store_code` | 逗号分隔的门店编码 | `0016` | + +> **重要**:`region` 字段存储的是**门店编码(store_code)**,不是区域名称。系统通过 `store_code = ANY(...)` 进行 SQL 过滤。 + +### 3.2 过滤逻辑 + +- **hq / dept**:无过滤,可查看本租户全部数据 +- **regional**:所有 API 查询自动注入 `store_code = ANY(门店编码列表)` +- **store**:所有 API 查询自动注入 `store_code = ANY(门店编码列表)` + +### 3.3 菜单权限 + +| 菜单 | hq | dept | regional | store | +|------|----|------|----------|-------| +| 老板驾驶舱 | ✅ | ✅ | - | - | +| 总部驾驶舱 | ✅ | ✅ | - | - | +| 态势感知 | ✅ | ✅ | ✅ | ✅ | +| 银行授信 | ✅ | - | - | - | +| 区域经理 | ✅ | ✅ | ✅ | - | +| 区域对比 | ✅ | ✅ | ✅ | - | +| 店长工作台 | ✅ | ✅ | - | ✅ | +| 任务管理 | ✅ | ✅ | ✅ | ✅ | +| 月度验收 | ✅ | ✅ | ✅ | - | +| 营收分析 | ✅ | ✅ | - | - | +| 平台优惠 | ✅ | ✅ | - | - | +| 会员复购 | ✅ | ✅ | - | - | +| 会员LTV | ✅ | ✅ | - | - | +| 菜品成本 | ✅ | ✅ | - | - | +| 成本库存 | ✅ | ✅ | - | - | +| 库存周转 | ✅ | ✅ | - | - | +| 中央厨房 | ✅ | ✅ | - | - | +| 配送对账 | ✅ | ✅ | - | - | +| BOM穿透 | ✅ | ✅ | - | - | +| 生产要货 | ✅ | ✅ | - | - | +| 门店费用 | ✅ | ✅ | - | - | +| 商品SKU | ✅ | ✅ | - | - | +| 菜单工程 | ✅ | ✅ | - | - | +| 时间分析 | ✅ | ✅ | - | - | +| 智能排班 | ✅ | ✅ | ✅ | ✅ | +| 员工绩效 | ✅ | ✅ | - | - | +| 风险内控 | ✅ | ✅ | - | - | +| 门店选址 | ✅ | ✅ | - | - | +| 用户管理 | ✅ | - | - | - | +| 数据质量 | ✅ | ✅ | - | - | +| 指标字典 | ✅ | ✅ | ✅ | ✅ | +| 本体标准 | ✅ | ✅ | - | - | + +前端路由守卫(RoleRoute)确保用户无法通过直接输入 URL 访问无权限的页面。 + +--- + +## 四、完整操作示例 + +### 场景:为新连锁品牌「B品牌」配置全套账号 + +#### 步骤 0:客户本机准备数据库 + frp 隧道 + +```bash +# === 在客户本机执行 === + +# 1. 创建数据库 +psql postgres -c "CREATE USER freedak SUPERUSER;" +psql postgres -c "CREATE DATABASE bill_query OWNER freedak;" + +# 2. 导入业务数据 +pg_restore -U freedak -d bill_query -1 /path/to/backup.dump + +# 3. 配置 frpc +cat > /etc/frp/frpc.toml << 'EOF' +serverAddr = "dm.all8ai.top" +serverPort = 7000 +auth.token = "frp_gitea_2026" +loginFailExit = false + +[[proxies]] +name = "tenant_b-db" +type = "tcp" +localIP = "127.0.0.1" +localPort = 5432 +remotePort = 16001 +EOF + +# 4. 启动 frpc +nohup frpc -c /etc/frp/frpc.toml > /var/log/frpc.log 2>&1 & + +# === 在服务器上验证 === +ssh ubuntu@152.136.182.184 "ss -tlnp | grep 16001" +# 应看到 LISTEN 状态 +``` + +#### 步骤 1:平台管理员创建租户 + +```bash +ADMIN_TOKEN=... # 平台管理员 token + +# 创建租户(db_port 和 frp_port 使用 frp 远程端口 16001) +curl -X POST http://localhost:9333/api/admin/tenants \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "tenant_id": "tenant_b", + "tenant_name": "B品牌连锁", + "db_host": "127.0.0.1", + "db_port": 16001, + "db_name": "bill_query", + "db_user": "freedak", + "db_password": "", + "frp_port": 16001 + }' + +# 激活租户 +curl -X PUT http://localhost:9333/api/admin/tenants/tenant_b \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"status": "active"}' + +# 验证数据库连接 +curl -s http://localhost:9333/api/admin/tenants/tenant_b/status \ + -H "Authorization: Bearer $ADMIN_TOKEN" +# 应返回 {"success":true,"data":{"connected":true}} + +# 创建总部管理员 +curl -X POST http://localhost:9333/api/admin/tenants/tenant_b/users \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "username": "brand_b_admin", + "password": "123", + "role": "hq", + "name": "B品牌管理员" + }' +``` + +#### 步骤 2:总部管理员创建区域经理和店长 + +```bash +HQ_TOKEN=... # brand_b_admin 的 token + +# 查询可用门店列表 +curl http://localhost:9333/api/admin/tenant/stores \ + -H "Authorization: Bearer $HQ_TOKEN" + +# 创建朝阳区区域经理(管辖门店 0001~0010) +curl -X POST http://localhost:9333/api/admin/tenant/users \ + -H "Authorization: Bearer $HQ_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "username": "chaoyang_manager", + "password": "123", + "role": "regional", + "name": "朝阳区区域经理", + "region": "0001,0002,0003,0004,0005,0006,0007,0008,0009,0010" + }' + +# 创建店长(管理 0001 号门店) +curl -X POST http://localhost:9333/api/admin/tenant/users \ + -H "Authorization: Bearer $HQ_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "username": "store_0001", + "password": "123", + "role": "store", + "name": "001号店长", + "store_code": "0001" + }' + +# 创建商品部 +curl -X POST http://localhost:9333/api/admin/tenant/users \ + -H "Authorization: Bearer $HQ_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "username": "product_dept", + "password": "123", + "role": "dept", + "name": "商品部", + "dept": "商品部" + }' +``` + +#### 步骤 3:验证登录 + +| 用户名 | 密码 | 角色 | 预期首页 | 数据范围 | +|--------|------|------|----------|----------| +| brand_b_admin | 123 | hq | 总部驾驶舱 | 全部门店 | +| chaoyang_manager | 123 | regional | 区域经理工作台 | 10 家朝阳区门店 | +| store_0001 | 123 | store | 店长工作台 | 仅 0001 号门店 | +| product_dept | 123 | dept | 总部驾驶舱 | 全部门店 | + +--- + +## 五、注意事项 + +1. **租户状态**:创建后默认 `inactive`,必须激活为 `active` 后用户才能登录 +2. **门店编码**:`region` 和 `store_code` 字段存储的是 `dim_store` 表中的 `store_code` 值,不是门店名称 +3. **多选门店**:店长和区域经理都可以关联多个门店,用逗号分隔 +4. **用户名唯一**:同一租户内用户名不能重复 +5. **密码安全**:密码使用 bcrypt 加密存储,无法逆向查看 +6. **路由守卫**:前端通过 RoleRoute 组件阻止越权访问,后端通过 data-scope 中间件过滤数据 +7. **删除用户**:删除用户不会影响已产生的业务数据 +8. **frp 隧道**:客户本机必须保持 frpc 运行,否则该租户所有 API 不可用。建议配置 `loginFailExit = false` 自动重连 +9. **frp 端口**:每个租户必须使用不同的远程端口,端口 15432 已被现有租户占用,新租户从 16001 开始递增 +10. **数据库密码**:如客户本机 PostgreSQL 使用密码认证(非 trust),需在创建租户时填写 `db_password` +11. **数据库离线**:客户本机关机/休眠会导致该租户 API 不可用,前端会显示错误提示 +12. **数据导入**:新租户的业务数据库必须导入完整的表结构和数据(analytics schema、dim_store 等),否则 API 会报错