当前数据库是本机Homebrew PostgreSQL 15,数据库名为 bill_query,端口5432,仅监听 localhost;当前用户 freedak 是超级用户,本机认证方式为 trust。这适合本机开发,但不适合直接照搬到服务器生产环境。前端浏览器也不应直接连接PostgreSQL,必须通过后端API访问。 ## 登录账号 ### 平台管理员 | 用户名 | 密码 | 角色 | 说明 | |--------|------|------|------| | 平台管理员 | 123 | platform_admin | 管理所有租户,登录后进入平台管理后台 | ### 租户用户(存储在服务器 sbrain_admin 数据库) | 用户名 | 密码 | 角色 | 租户 | |--------|------|------|------| | 总部管理员 | 123 | hq | tenant_a(西部马华) | > 租户管理员(hq)登录后可在系统内创建区域经理、店长、商品部等角色用户。 > 密码使用 bcrypt 加密存储。 ## 架构(2026-08-02 更新:SaaS 多租户) ``` 浏览器 → https://dm.all8ai.top → Nginx(服务器) → /api/ → 127.0.0.1:9333 (服务器后端, pm2管理) → 服务器本地 PostgreSQL:5432 → sbrain_admin(平台库:租户配置、用户认证) → frp隧道 127.0.0.1:15432 → 本机PostgreSQL:5432 → bill_query(租户业务库) ``` ### 数据库连接(重要) 后端连接两个不同的数据库,走不同端口: | 连接池 | 目标数据库 | 连接地址 | 认证方式 | 配置来源 | |--------|-----------|---------|---------|---------| | `adminPool` | `sbrain_admin`(平台库) | `127.0.0.1:5432`(服务器本地 PG) | scram-sha-256(用户 `sbrain_admin`,密码 `sbrain2026`) | `.env` 中 `ADMIN_DB_*` | | `tenantPool` | `bill_query`(业务库) | `127.0.0.1:15432`(FRP 隧道 → 本机 PG) | trust(用户 `freedak`,无需密码) | `tenant_configs.db_port=15432` | | `pool` | `bill_query`(业务库) | `127.0.0.1:15432`(FRP 隧道 → 本机 PG) | trust(用户 `freedak`,无需密码) | `.env` 中 `DB_*` | > ⚠️ `tenant_configs` 表中 `db_port` 必须为 `15432`(FRP 隧道),`db_password` 为 NULL(trust 认证)。 > ⚠️ `adminPool` 连接服务器本地 5432,需要 `ADMIN_DB_PASSWORD=sbrain2026`。 ### 数据库分布 | 数据库 | 位置 | 存储内容 | |--------|------|---------| | `sbrain_admin` | 服务器本地 PostgreSQL(5432) | 平台管理员、租户配置(tenant_configs)、所有租户用户(tenant_users) | | `bill_query` | 本机 PostgreSQL(通过 frp 暴露为 15432) | 租户业务数据(销售、任务、成本分析等) | ### 多租户数据隔离 - **认证流程**:用户登录 → 查 `sbrain_admin.tenant_users` → bcrypt 验证 → JWT 含 `tenantId` - **数据隔离**:业务请求 → `tenantDbMiddleware` 根据 JWT 中的 `tenantId` 查 `tenant_configs` 获取该租户数据库连接信息 → `AsyncLocalStorage` 设置租户连接池 → 所有 `query()` 自动走对应租户数据库 - **租户用户管理**:平台管理员为租户创建管理员(hq),租户管理员在系统内创建区域经理/店长/商品部等用户,均存储在 `sbrain_admin.tenant_users` 表中,通过 `tenant_id` 字段区分 ### 关键文件 | 文件 | 职责 | |------|------| | `server/src/config/tenant-db.ts` | 租户连接池缓存 + AsyncLocalStorage | | `server/src/config/admin-pool.ts` | 平台库连接池(通过 `ADMIN_DB_*` 环境变量配置) | | `server/src/config/database.ts` | 主业务库连接池 + 全局 `query()` 函数(自动注入数据权限) | | `server/src/middleware/tenant-db.ts` | 根据 JWT tenantId 动态切换数据库 + 注入用户 scope | | `server/src/middleware/data-scope.ts` | 数据权限工具函数(`getDataScope` / `scopeStoreFilter`) | | `server/src/routes/auth.ts` | 租户用户登录(查 tenant_users + bcrypt) | | `server/src/routes/admin.ts` | 平台管理 API + 租户内用户管理 API | | `server/sql/11_tenant_management.sql` | 平台数据库建表 SQL | ## 部署流程 ### 一键部署(前端+后端) ```bash bash deploy.sh # 全量部署(后端+前端) bash deploy.sh server # 只部署后端 bash deploy.sh front # 只部署前端 ``` - 后端:rsync 同步到服务器 `/opt/sbrain-server` + npm install + pm2 重启 - 前端:构建 + scp 上传到服务器 `/var/www/dm.all8ai.top` ### 本机 frp 隧道(launchd 系统级服务) frpc 配置(`/Users/freedak/frp/frpc.toml`): ```toml serverAddr = "152.136.182.184" serverPort = 7000 loginFailExit = false auth.token = "frp_gitea_2026" [[proxies]] name = "dm-db" type = "tcp" localIP = "127.0.0.1" localPort = 5432 remotePort = 15432 ``` 已配置为 macOS launchd 系统级服务,开机自动启动,崩溃自动重启,与 IDE 无关。 | 服务 | plist | 日志 | |------|-------|------| | frp 隧道 (5432→15432) | `~/Library/LaunchAgents/com.frp.client.plist` | `~/Library/Logs/frpc.log` | #### 管理命令 ```bash # 停止 frpc launchctl bootout gui/$(id -u)/com.frp.client # 启动 frpc launchctl load ~/Library/LaunchAgents/com.frp.client.plist # 查看日志 tail -f ~/Library/Logs/frpc.log # 检查状态 pgrep -l frpc curl -s https://dm.all8ai.top/api/health ``` #### 手动启动 frpc(备用,launchd 未运行时) ```bash cd /Users/freedak/frp && ./frpc -c frpc.toml & ``` ## 本地开发 ### 后端开发 ```bash cd server && npm run dev ``` 后端运行在 `http://localhost:3333`,连接本地 PostgreSQL(`localhost:5432`,数据库 `bill_query`)。 ### 前端开发 ```bash cd client && npm run dev ``` 访问 `http://localhost:5173`(Vite proxy 自动转发 `/api` 到 `localhost:3333`)。 ## 服务器后端管理 ```bash # 查看后端状态 ssh ubuntu@152.136.182.184 'pm2 status sbrain-server' # 查看后端日志 ssh ubuntu@152.136.182.184 'pm2 logs sbrain-server --lines 50' # 重启后端 ssh ubuntu@152.136.182.184 'pm2 restart sbrain-server' # 查看后端 .env ssh ubuntu@152.136.182.184 'cat /opt/sbrain-server/.env' ``` ## 数据库直连命令(调试用) ### 业务库 bill_query(通过 SSH 隧道连服务器 FRP 端口) ```bash # 从本机通过 SSH 连接服务器,再连 FRP 隧道端口 15432(→ 本机 PG 5432) ssh ubuntu@152.136.182.184 "PGPASSWORD= psql -U freedak -h 127.0.0.1 -p 15432 -d bill_query -c \"SELECT count(*) FROM analytics.mv_store_risk_rating_monthly\"" # 多行 SQL 用双引号包裹,内部用单引号 ssh ubuntu@152.136.182.184 "PGPASSWORD= psql -U freedak -h 127.0.0.1 -p 15432 -d bill_query -c \" SELECT store_name, risk_level, received FROM analytics.mv_store_risk_rating_monthly WHERE month_start = '2026-04-01' ORDER BY received DESC LIMIT 5 \"" ``` ### 平台库 sbrain_admin(服务器本地 PG 5432,需密码) ```bash ssh ubuntu@152.136.182.184 "PGPASSWORD=sbrain2026 psql -U sbrain_admin -h 127.0.0.1 -p 5432 -d sbrain_admin -c \"SELECT username, role FROM tenant_users\"" ``` ### 连接参数速查 | 数据库 | SSH 目标 | 端口 | 用户 | 密码 | PGPASSWORD | |--------|---------|------|------|------|------------| | bill_query(业务库) | ubuntu@152.136.182.184 | 15432 | freedak | 无(trust) | 空 | | sbrain_admin(平台库) | ubuntu@152.136.182.184 | 5432 | sbrain_admin | sbrain2026 | sbrain2026 | > ⚠️ 业务库 15432 是 FRP 隧道端口,映射到本机 PG 5432。frpc 断开后 15432 不可用。 > ⚠️ 平台库 5432 是服务器本地 PostgreSQL,需 SCRAM 认证。 > ⚠️ SSH 命令中嵌套 psql 时,外层用双引号、内层 SQL 用双引号转义(`\"`),SQL 字符串用单引号。 ## 注意事项 - **平台库 `sbrain_admin` 在服务器本地 PostgreSQL(5432)**,业务库 `bill_query` 在本机 PostgreSQL(通过 frp 暴露为 15432) - `adminPool` 连服务器本地 5432 的 `sbrain_admin`(SCRAM 认证,用户 `sbrain_admin`,密码 `sbrain2026`) - `tenantPool` / `pool` 连 FRP 隧道 15432 的 `bill_query`(trust 认证,用户 `freedak`,无需密码) - `tenant_configs` 表中 `db_port` 必须为 `15432`,`db_password` 为 NULL(trust 认证) - `pg` 库在 `password` 为空字符串时会触发 SCRAM 认证失败,因此 `admin-pool.ts`、`database.ts`、`tenant-db.ts` 中空密码时不传 `password` 参数 - `deploy.sh` 每次部署会覆盖服务器 `.env`,其中包含 `ADMIN_DB_*` 配置(`ADMIN_DB_PORT=5432`,`ADMIN_DB_PASSWORD=sbrain2026`),修改 `.env` 配置必须同步修改 `deploy.sh` - 租户用户统一存储在 `sbrain_admin.tenant_users` 表,通过 `tenant_id` 区分租户 - `tenant_users.region` 字段为 `VARCHAR(500)`,区域经理的 `region` 存储逗号分隔的 `store_code` 列表(如 `0010,0011,0014`) - 密码使用 bcrypt 加密,平台管理员密码目前仍为明文(后续可改) - 本机只需运行 frpc(launchd 自启),后端已部署到服务器 - 修改后端代码后执行 `bash deploy.sh server` 部署到服务器 - 修改前端代码后执行 `bash deploy.sh front` 部署到服务器 - 全量部署执行 `bash deploy.sh`(后端+前端) - `server/.env`(本机开发用)中 `DB_PORT=5432` 连接本地数据库,不要改为 5433 - 服务器 `/opt/sbrain-server/.env` 中 `DB_PORT=15432` 连接 frp 隧道端口 - frpc 断开后线上前端 API 会失效,需重新启动 frpc - launchd 服务开机自启,关闭 IDE/终端不影响;仅注销/关机时停止,下次登录/开机自动恢复 0.1/0.2分支为 SBrainCO,备份在/Volumes/Projects/2026/SBrainCO-20260805.zip 0.3分支为 SBrainCO3