Files
SMANAGE/SAAS_ARCHITECTURE.md
T

270 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SAAS 架构概览
> 面向技术决策会议的架构说明文档。本文档聚焦 SAAS 多租户-公司-部门-用户-角色架构设计、当前实现状态与未来发展方向。
---
## 1. 项目定位
**GVS-DSDK** 是一套面向中小企业(SMB)的 SAAS 化企业管理平台,包含:
- **多租户 SAAS 框架**:支持租户入驻、审核、隔离
- **企业资源管理(GERP)**:组织、角色、权限、菜单、工单、资产、文档
- **三大业务引擎**:分佣引擎、支付网关、统计引擎
- **分布式通信底座(MSYNC)**:服务注册、发现、分布式事务
## 2. 技术栈
| 层 | 技术 |
|---|---|
| 后端框架 | Django 4.2+ / DRF / SimpleJWT |
| 异步任务 | Celery + Redis(可降级同步) |
| 实时通信 | Socket.IO(python-socketio) |
| 数据库 | MySQL 5.7+(7 库分库路由) |
| 缓存 | Redis(可降级 locmem) |
| 安全 | bcrypt / AES-256-GCM / JWT |
| 前端 | 原生 HTML/JS + 自研 NeoUI/GERPUI 组件 |
| 部署 | Gunicorn + Nginx 反向代理 |
## 3. 双包架构
```
┌─────────────────────────────────────────────────────┐
│ d:\SMANAGE(项目根) │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐│
│ │ gvsds │ │ gvsdsdk ││
│ │ 主服务器(业务层) │◄─┤ 分布式 SDK(薄封装)││
│ │ - Django 项目 │ │ - 协议契约层 ││
│ │ - 14 个业务 App │ │ - 惰性加载 ││
│ │ - 完整业务实现 │ │ - PascalCase 协议 ││
│ └──────────────────────┘ └──────────────────────┘│
│ ▲ ▲ │
│ │ │ │
│ ┌──────────────────────┐ ┌──────────────────────┐│
│ │ ATestCServer │ │ TempLate/ ││
│ │ 子服务器示例 │ │ 前端模板资源 ││
│ │ 通过 SDK 接入 │ │ GERP/AKS/MSOC 等 ││
│ └──────────────────────┘ └──────────────────────┘│
└─────────────────────────────────────────────────────┘
```
### 3.1 `gvsds` — 主服务器
- 14 个 Django App:`core / gerp / ugm / crb / invite / ccgo / sve / t4 / mc / doc / api / msync / payment / commission / stats`
- 7 库分库路由:`Users / GerpCore / Plans / Tasks / T4PC / Document / Minecraft`
- 6 个自定义中间件:IP 过滤、域名注入、当前角色注入、服务认证、攻击检测、错误日志
### 3.2 `gvsdsdk` — 分布式 SDK
- **薄封装层**:1:1 包装 `gvsds.apps.msync` 原生层,无运行时开销
- **惰性加载(PEP 562)**:90+ 符号按需 import
- **双类导出**:自有实现(无 Django 依赖,子服务器可用)+ 服务端转发(依赖 Django ORM)
- **三大引擎**:`CommissionEngine`(分佣)、`PaymentManager`(支付)、`TransactionManager`(分布式事务)
### 3.3 主从通信机制
- **版本校验**:启动时 `gvsdsdk.check_min_version('1.0.0')`,主从必须一致
- **Socket.IO 协议**:20+ 事件,全程 PascalCase 字段
- **支付网关自动注册**:`gvsdsdk/apps.py` 的 `ready()` 钩子
---
## 4. SAAS 多租户架构(核心)
### 4.1 组织四层架构
```
┌──────────────────────────────────────────────────────────┐
│ 第 4 层:鉴权规则层(运行时) │
│ 操作权限 (RBAC) 数据权限 (ABAC + RoleScope) │
├──────────────────────────────────────────────────────────┤
│ 第 3 层:角色权限载体层 │
│ Role + UserRole + RolePermission │
├──────────────────────────────────────────────────────────┤
│ 第 2 层:岗位模板层(初始化快照) │
│ PositionTemplate + PositionTemplatePermission │
│ CopyToRole 一次性复制,后续独立演进 │
├──────────────────────────────────────────────────────────┤
│ 第 1 层:组织人事层 │
│ Tenant → Company → Department │
│ UserDept(员工-部门多对多) │
│ Position(人事职务标签,与权限解耦) │
│ Workgroup(跨部门工作组) Shop(商铺,归公司) │
└──────────────────────────────────────────────────────────┘
```
### 4.2 数据模型核心表(共 17 张 SAAS 表)
| 分类 | 表名 | 职责 |
|---|---|---|
| **租户** | `Tenant` | 多租户根,含审核状态/到期时间 |
| **组织** | `Company` / `CompanyInfo` / `Department` / `Workgroup` | 公司树/工商信息/部门树/跨部门组 |
| **用户** | `User` / `UserAvatar` / `User2FA` / `UserPending2FA` / `UserLoginLog` / `AccountActivation` / `Password` / `UserIDCard` | 用户身份与认证 |
| **角色权限** | `Role` / `Permission` / `UserRole` / `RolePermission` | RBAC 核心 |
| **岗位模板** | `PositionTemplate` / `PositionTemplatePermission` | 权限初始化快照 |
| **人事标签** | `Position` / `UserDept` | 职务标签(与权限解耦) |
| **商铺** | `Shop` / `RoleShop` | 多商铺体系 |
| **ABAC** | `UserABAC` | 属性访问控制(补充) |
| **审计** | `AuditLog` / `AbnormalUserLog` | 操作审计 + 攻击溯源 |
### 4.3 关键设计决策
#### (1) Position 与权限**完全解耦**
- 人事职务标签(`Position`)仅用于人事管理,**不直接绑定权限**
- 调岗/升职只修改 `UserDept.PositionUUID` 与 `UserRole`,权限只通过 `UserRole → RolePermission → Permission` 走
- 规避了业界常见错误:把职务直接绑权限导致调岗时权限树重算
#### (2) PositionTemplate 的"快照复制"机制
- 模板 → 角色 = **一次性复制**(`CopyToRole`),复制后两者无运行时绑定
- 模板调整只影响**之后新建**的角色,已有角色不被动变更
- 避免了"模板改一个字段,全员权限突然变了"的运维灾难
#### (3) UserRole 作为**胖关联表**
`UserRole` 表同时承载三重语义:
- **权限分配**:User ↔ Role 多对多
- **组织归属**:携带 `CompanyUUID / DeptUUID / WorkgroupUUID`
- **数据范围**:`RoleType` 标识"普通成员/部门负责人"
**优势**:同一用户在不同公司/部门可绑不同角色,原生支持 SAAS 强需求
**代价**:UserRole 违反单一职责,未来扩展需谨慎
#### (4) 角色作用域四档数据权限(`RoleScope`)
| 类型 | 判定条件 | 可见范围 |
|---|---|---|
| `admin` | IsSuperuser/IsStaff 或 `admin:super` 权限 | 全公司 |
| `dept_manager` | `UserRole.RoleType=1` 且 `DeptUUID` 非空 | 本部门成员 |
| `workgroup_lead` | `UserRole.RoleType=1` 且 `WorkgroupUUID` 非空 | 本工作组成员 |
| `member` | 其他 | 仅自己 |
### 4.4 运行时鉴权流程
```
HTTP Request
│
├─► JWTAuthentication → User 实例
├─► CurrentRoleMiddleware → request.current_role (Role)
├─► DomainMiddleware → request.current_company_uuid
│
├──► 操作权限校验:PermissionVerifier(permission, attrs, user, request)
│ ├─ ABAC:UserABAC.HierarchicalPermissionIdentifiers ∋ attr?
│ └─ RBAC:RolePermission(角色)→Permission.PermCode ∋ attr?
│ (含请求级缓存,消除 N+1)
│
└──► 数据权限校验:RoleScope.GetUserScope(request)
└─ ApplyScopeToQueryset(qs, scope, table_name)
按 admin/dept_manager/workgroup_lead/member 差异化过滤
```
### 4.5 主键设计
- 全程使用 `BINARY(16)` UUID 主键
- 优势:分布式生成、无 ID 冲突、不暴露顺序信息
- 代价:InnoDB 聚簇索引无序,写入有页分裂开销(可考虑改 UUIDv7)
---
## 5. 三大业务引擎
### 5.1 分佣引擎(`CommissionEngine`)
| 策略 | Type | 说明 |
|---|---|---|
| `PercentageStrategy` | `percentage` | 比例分账,支持保底/封顶 |
| `FixedStrategy` | `fixed` | 固定金额 |
| `TieredStrategy` | `tiered` | 阶梯分账 |
| `RemainderStrategy` | `remainder` | 剩余归平台 |
| `WithdrawalFeeStrategy` | `withdrawal_fee` | 提现手续费 |
支持:规则配置 → 触发分佣 → 预结算 → 邀请链分佣 → 查询统计
### 5.2 支付网关(`PaymentManager`)
| 渠道 | 支付方式 | 转账 |
|---|---|---|
| 微信支付 | JSAPI/Native/H5/小程序 | 支持 |
| 支付宝 | APP/H5/Native | 支持 |
| 银行卡 | APP/H5/Native | 仅 bank 类型 |
支持:网关配置 → 支付/查询/退款/转账 → 回调处理
### 5.3 统计引擎(`stats`)
- Celery 定时任务:每日重置 / 每月重置 / 排行榜构建 / 过期清理
- 按角色差异化仪表盘
---
## 6. 当前实现状态
### 6.1 已完成
- ✅ 14 个业务 App 完整实现
- ✅ 多租户入驻审核工作流
- ✅ RBAC + ABAC 混合鉴权
- ✅ 分佣引擎 + 支付网关 + 统计引擎
- ✅ MSYNC 分布式通信(注册/发现/OGM/Saga 事务)
- ✅ 文件分片上传 + 资产管理
- ✅ 操作审计日志 + 攻击检测
### 6.2 已知技术债
| 优先级 | 问题 | 影响 |
|---|---|---|
| 高 | Role/Permission 模型在 gvsds 与 gvsdsdk 双份定义 | 字段漂移风险 |
| 高 | 部分表(User/Dept/Workgroup/Shop)无 TenantUUID | 跨租户查询需 JOIN,删除租户困难 |
| 中 | ABAC 实现本质是 RBAC(字符串集合) | 名实不符,扩展受限 |
| 中 | 数据权限硬编码 `if table_name == 'X'` | 违反开闭原则 |
| 中 | 缺乏软删除机制 | 误删不可恢复 |
| 低 | UUID 主键无序导致索引膨胀 | 大数据量写入性能下降 |
| 低 | 根 README.md 仍为 Flask 时代文档 | 新人易误读 |
---
## 7. 未来发展方向(会议讨论建议项)
### 7.1 短期(1-3 个月)
1. **统一 Role/Permission 模型**:让 gerp 直接复用 gvsdsdk 的模型定义,消除双份漂移
2. **补全 TenantUUID 字段**:所有租户语义表直接打 `TenantUUID`,简化跨租户查询与租户删除
3. **数据权限策略化**:用策略模式替代 `if table_name == 'X'`,每个模型注册自己的 `ScopeFilter`
4. **更新根 README.md**:反映当前 Django 架构
### 7.2 中期(3-6 个月)
1. **重构 ABAC 为真正的属性访问控制**:支持时间/IP/资源所有者/字段级权限
2. **引入软删除机制**:`DeletedAt` + `DeletedByUUID`,配合审计日志实现数据恢复
3. **支付网关扩展**:增加 PayPal/Stripe 适配(出海场景)
4. **租户配额管理**:用户数/数据量/API 调用次数配额
### 7.3 长期(6+ 个月)
1. **拆分协议层**:把 gvsdsdk 拆为 `gvsds-protocol`(纯协议)+ `gvsds-business`(业务能力),主从各自依赖
2. **改用 UUIDv7 或 Snowflake**:解决主键无序问题
3. **多区域部署**:基于 MSYNC 实现跨地域多活
4. **微服务化拆分**:gerp/payment/commission/stats 可独立部署
---
## 8. 关键架构原则
1. **PascalCase 全链路一致**:从数据库字段 → Python 类 → Socket.IO 事件 → 前端,无转换层
2. **优雅降级**:Redis/Celery/网关依赖缺失时自动降级,开发环境零依赖启动
3. **配置外置**:`app.ini` + `secrets.ini` + 环境变量三层配置,支持 12-factor 部署
4. **薄封装 SDK**:协议契约层与业务实现层分离,主从可独立演进
5. **Position 与权限解耦**:人事标签不绑权限,避免调岗重算
---
## 9. 联系与维护
- **主仓库**:`d:\SMANAGE`
- **SDK 包**:`gvsdsdk/`(pyproject.toml v1.0.0)
- **子服务器示例**:`ATestCServer/`
- **设计文档**:`docs/commission_engine.md` / `docs/payment_gateway.md` / `docs/stats_engine.md`
---
**本架构文档用于技术决策会议参考,详细 API 与字段定义见 [gvsdsdk/API.md](file:///d:/SMANAGE/gvsdsdk/API.md) 与 [gvsdsdk/README.md](file:///d:/SMANAGE/gvsdsdk/README.md)。**