第02天 [架构] 总体架构与多租户设计

0 阅读8分钟

第02天 [架构] 总体架构与多租户设计

今日寄语:"糟糕的程序员担心代码,优秀的程序员担心数据结构和它们之间的关系。" —— Linus Torvalds


[注意] 2.0 今日导读

前置依赖:

  • [√] 完成第01天:明确学习路径和MVP范围

  • [√] 了解低代码平台的核心概念

  • [√] 熟悉基本的架构设计原则

核心产出:

  • 📐 MetaFlow 七层架构设计图

  • 🏢 多租户方案选型与实现方案

  • 📁 Monorepo 项目骨架

  • 📋 核心模块接口定义(OpenAPI)

预计耗时:

  • [指南] 阅读理解: 30-45分钟

  • [实践] 必做作业: 60-90分钟

  • [*] 选做挑战: 2-3小时

AI 结对策略:

让 AI 扮演架构师,帮你审查模块依赖、生成 OpenAPI (Swagger) 定义草案、分析性能瓶颈。


2.1 写在最前面:架构决定成败

在低代码平台开发中,架构设计就像是建筑的地基。地基不牢,地动山摇。今天我们要搭建的不仅仅是一个技术框架,更是整个平台的"定海神针"。

[提示] AI 加速提示:今天我们将使用 AI 来生成架构文档、审查模块依赖、创建 OpenAPI 定义。


2.2 七层架构模型:系统的骨架

低代码平台之所以复杂,是因为它既是生产工具(Designer),又是运行环境(Runtime)。为了解耦,我们将系统划分为七层。


graph TD

subgraph Client [第一层:交互层 (Presentation)]

Web[Web 端 (React)]

Mobile[H5/小程序]

IDE[IDE 设计器]

end

  


subgraph Gateway [第二层:接入层 (Gateway)]

Nginx[Nginx / Ingress]

Auth[认证鉴权 (Auth Guard)]

Rate[限流熔断]

Error[全局错误处理]

end

  


subgraph App [第三层:应用组装层 (App Orchestration)]

PageEngine[页面渲染引擎]

FlowEngine[流程编排引擎]

ApiProxy[API 聚合代理]

Validation[数据校验引擎]

end

  


subgraph Core [第四层:核心领域层 (Domain Core)]

Meta[元数据服务 (Metadata Service)]

Modeling[数据建模 (Modeling Service)]

Workflow[工作流内核 (Workflow Kernel)]

Rbac[权限内核 (RBAC Core)]

Script[脚本引擎]

end

  


subgraph Support [第五层:通用支撑层 (Support)]

Plugin[插件机制]

Event[事件总线]

Job[定时任务]

Cache[缓存管理]

Log[日志服务]

end

  


subgraph Data [第六层:数据持久层 (Persistence)]

MetaDB[(元数据 DB - SQLite/PG)]

BizDB[(业务数据 DB - SQLite/PG/MySQL)]

CacheDB[(缓存 - Redis)]

FileStore[(文件存储 - MinIO)]

end

  


subgraph Infra [第七层:基础设施层 (Infrastructure)]

K8s[Kubernetes]

OSS[对象存储]

LLM[LLM 网关]

Monitor[监控系统]

end

  


Client --> Gateway

Gateway --> App

App --> Core

Core --> Support

Core --> Data

Support --> Infra

关键决策点

  1. 元数据与业务数据分离
  • MetaDB:存储"页面长什么样"、"表有哪些字段"。这是平台的灵魂。

  • BizDB:存储用户实际录入的"张三"、"隐患单"。这是用户的资产。

  • 为什么分离? 为了方便平台升级。MetaDB 升级不应影响 BizDB 的数据完整性。

  1. 引擎与设计器解耦
  • 设计器只负责生成 JSON。

  • 应用组装层只负责消费 JSON。两者通过标准 Schema 通信,互不依赖。

  1. 错误处理层:新增全局错误处理,确保系统稳定性。

  2. 脚本引擎:将脚本执行能力下沉到核心领域层,便于统一管理。


2.3 多租户设计:ToB 的必修课

多租户(Multi-Tenancy)是 SaaS 的基石。如果在 Day 02 不定下来,Day 15 再改就是灾难。

2.3.1 常见策略对比

| 策略 | 描述 | 优点 | 缺点 | 适用场景 |

| :--- | :--- | :--- | :--- | :--- |

| 独立数据库 (Database per Tenant) | 每个租户一个 DB | 数据绝对隔离,安全,可单独备份 | 成本极高,运维噩梦 | 银行/政企大客户 |

| 独立 Schema (Schema per Tenant) | 共享 DB,独立 Schema | 隔离性好,成本适中 | 跨租户统计难,迁移略繁琐 | 中型 SaaS |

| 共享 Schema (Discriminator) | 共享表,加 tenant_id 字段 | 成本最低,开发最快 | 代码容易写漏,数据泄露风险 | MVP 首选 |

2.3.2 我们的选择:Discriminator(MVP)+ 生产 RLS 兜底 + 中间件防护

为了 21 天能交付,我们选择 共享 Schema (Discriminator) 模式。

[警告] 风险提示

共享 Schema 模式在代码层面容易出现漏洞(如开发者忘记加 where 条件),可能导致严重的数据泄露。对于金融、医疗等对数据隔离要求极高的场景,必须采用物理隔离(独立数据库或独立 Schema)。

为了安全,我们采用三层防护(其中数据库层仅在生产 PostgreSQL 启用):

设计规范

  1. 所有表(除了系统配置表)必须包含 tenant_id 字段。

  2. ORM 层拦截:在 Prisma Client 中通过 Middleware 自动注入 tenant_id 过滤条件。

  3. 数据库层防护(生产 PostgreSQL):利用 RLS (行级安全策略) 作为兜底。

  4. 应用层验证:在业务逻辑层再次验证租户权限。

2.3.3 技术实现示例


// prisma/tenant.middleware.ts

import { Prisma } from '@prisma/client';

  


export const tenantMiddleware = (tenantId: string): Prisma.Middleware => {

return async (params, next) => {

// 自动添加 tenant_id 过滤条件

if (params.model && params.action.startsWith('find')) {

if (!params.args.where) {

params.args.where = {};

}

params.args.where.tenantId = tenantId;

}

// 创建操作自动添加 tenant_id

if (params.action === 'create') {

if (params.args.data) {

params.args.data.tenantId = tenantId;

}

}

return next(params);

};

};

实现备注(MVP):当前示例以 SQLite 本地开发为主;生产部署建议切换 PostgreSQL 并启用 RLS(行级安全),同时保留应用层的 Header 注入与服务端校验双保险。

完整实现与更多错误映射见附录:多租户中间件与 RLS 策略


2.4 模块拆分与目录结构 (Monorepo)

我们使用 TurboRepo 管理 Monorepo。结构如下:


metaflow/

├── apps/

│ ├── web/ # 前端:设计器 + 运行时 (React)

│ └── server/ # 后端:API 服务 (NestJS)

├── packages/

│ ├── database/ # 共享:Prisma Schema 与 Client

│ ├── shared-types/ # 共享:前后端通用的 TS 类型定义

│ ├── ui/ # 共享:基础 UI 组件库

│ ├── logic-engine/ # 核心:前端逻辑解析引擎 (纯 JS 库)

│ ├── validation/ # 共享:数据校验引擎

│ └── utils/ # 共享:工具函数库

├── docker/ # 部署配置

└── docs/ # 文档

为什么把 logic-engine 独立?

因为逻辑引擎需要在两端运行:

  • 浏览器端:实时计算表单联动(如:金额 > 1000 显示审批人)。

  • 服务端:提交数据时进行二次校验(防止恶意篡改前端逻辑)。

独立发包可以确保前后端逻辑的一致性。


2.5 AI 结对编程实战:定义接口契约

架构定好了,接下来该写接口定义了。这时候别自己哼哧哼哧写 YAML,让 AI 来帮你。

2.5.1 Prompt 示例

:我正在开发一个低代码平台,后端使用 NestJS。请帮我定义"应用管理(App Management)"模块的 RESTful API 接口。

要求:

  1. 遵循 OpenAPI 3.0 标准。
  1. 包含创建、列表、详情、发布四个接口。
  1. 字段包含:id, name, description, icon, status (draft/published), created_by, tenant_id。
  1. 加上 Swagger 装饰器示例代码。
  1. 包含请求/响应 DTO 定义。
  1. 添加错误处理和验证规则。

Claude/ChatGPT:没问题,这是为您生成的 apps.controller.ts 和 DTO 代码...

2.5.2 更高级的 AI 应用

架构审查

Prompt:请审查以下七层架构设计,指出潜在的问题和改进建议。

性能优化建议

Prompt:基于这个架构设计,请分析可能的性能瓶颈,并提供优化建议。


2.6 性能与安全考虑

性能优化策略

  1. 缓存策略:元数据缓存、页面模板缓存

  2. 数据库优化:索引优化、查询优化

  3. 前端优化:虚拟滚动、懒加载、代码分割

安全防护措施

  1. 输入验证:所有接口都必须有严格的输入验证

  2. 权限控制:RBAC + ABAC 双重验证

  3. 数据加密:敏感数据加密存储

  4. 审计日志:关键操作记录审计日志


2.7 今日作业

[√] 必做任务 (预计 90-120分钟)

任务1: 初始化Monorepo项目 (预计 30分钟)

  1. 使用 TurboRepo 或 pnpm workspace 初始化

  2. 创建 apps/(web+server) 和 packages/(database+shared-types) 目录

  3. 配置统一的 tsconfig.json.eslintrc

  4. 验收标准: pnpm install 成功,所有package能相互引用

任务2: 设计Prisma Schema (预计 40分钟)

  1. packages/database/prisma/schema.prisma 创建Schema

  2. 定义 User, Tenant, App 三张核心表

  3. 每张表必须包含 tenant_id 字段(除Tenant表外)

  4. 验收标准: npx prisma generate 成功生成Client

任务3: 实现多租户中间件 (预计 30分钟)

  1. 创建 tenant.middleware.ts

  2. 拦截所有Prisma查询,自动注入 where: { tenantId }

  3. 验收标准: 查询User时自动过滤当前租户数据

[*] 选做挑战 (预计 2-3小时)

  1. 架构审查: 使用AI分析知名SaaS产品的多租户方案

  2. RLS策略: 研究PostgreSQL RLS并编写示例

  3. 压测方案: 设计七层架构的性能瓶颈分析

[提示] 详细代码模板见附录B


[√] 2.8 今日检查点

请确认你已经:

  • 理解七层架构的设计原则和每层职责

  • 掌握三种多租户策略的适用场景

  • 了解 Discriminator + RLS 三层防护机制

  • 熟悉 Monorepo 项目结构和模块划分

  • 能够使用 AI 生成 OpenAPI 接口定义

  • 完成 Prisma Schema 基础设计

  • 实现了多租户中间件原型

[提示] 检查方法: 尝试画出七层架构图和数据流向图,如果能独立画出并解释,说明已掌握核心概念。


[笔记] 2.9 要点回顾

  1. 七层架构: 交互层 → 接入层 → 应用组装层 → 核心领域层 → 通用支撑层 → 数据持久层 → 基础设施层

  2. 多租户方案: MVP选择Discriminator(共享Schema),生产环境用PostgreSQL RLS兜底

  3. 三层防护: ORM中间件 + 应用层验证 + 数据库RLS策略

  4. Monorepo结构: apps/(web+server) + packages/(database+shared-types+logic-engine等)

  5. AI加速: 架构审查、接口生成、性能分析、文档撰写


[参考] 2.10 延伸阅读

  • [Book] Clean Architecture by Robert C. Martin: 深入研究分层架构的设计原则

  • [Book] Designing Data-Intensive Applications by Martin Kleppmann: 第6章关于分区与多租户数据的讨论

  • [Article] Multi-Tenant Data Architecture: Microsoft 的多租户架构最佳实践

  • [Doc] PostgreSQL Row Level Security: 官方RLS文档与最佳实践


❓ 2.11 常见问题

Q1: 为什么选择共享 Schema 而不是独立数据库?

A: MVP阶段优先考虑开发速度和成本。独立数据库虽然安全性最高,但运维复杂度和成本都很高。对于大部分ToB场景,Discriminator + RLS双重防护已经足够安全。

Q2: 七层架构是不是太复杂了?

A: 对于MVP来说,不需要一次性实现所有层。可以先实现核心的3-4层,其他层随着需求增长逐步补充。重要的是理解分层思想。

Q3: Monorepo 和 MultiRepo 该如何选择?

A: 低代码平台的前后端、多个Package高度耦合,共享大量类型定义,Monorepo可以简化依赖管理和版本同步。如果团队规模大于50人,可考虑MultiRepo。

Q4: 为什么要把 logic-engine 独立出来?

A: 逻辑引擎需要在浏览器端和服务端都执行,独立发包可确保前后端使用完全相同的逻辑,避免不一致导致的安全漏洞。