讨论日期:2026-07-07 · 状态:方案讨论
软件工厂计划从系统层面提供一个共享的 PostgreSQL 实例,供两类场景使用:
核心诉求:
采用 PostgreSQL Schema 级隔离。
| 方案 | 优点 | 缺点 | 结论 |
|---|---|---|---|
| Schema 隔离 | 隔离边界清晰、运维简单、单实例即可 | schema 数量极多时需注意 PG catalog 膨胀 | 采用 |
| Database 隔离 | 最强隔离 | 运维复杂,跨库查询困难 | 过重 |
| RLS 行级隔离 | 最省资源 | 一个 policy 写漏就泄露;用户能看到其他人的表名 | 风险高 |
PostgreSQL 实例 │ ├─ system schema ← 系统表,用户角色无任何权限 │ ├─ projects │ ├─ users │ └─ ... │ ├─ tenant_proj_001 ← 项目 A 的独立空间 │ ├─ (用户自建的表) │ └─ ... │ ├─ tenant_proj_002 ← 项目 B 的独立空间 │ └─ ... │ └─ public schema ← 可选:放共享扩展(如 uuid-ossp)
blade_system),拥有 system schema 的全部权限system schema 没有任何权限,连 SELECT 都不行tenant_proj_001)search_path = tenant_proj_xxx, public,用户应用直接写 SQL 即可,无需感知 schema 前缀ALTER ROLE tenant_proj_001 SET statement_timeout = '30s'; ALTER ROLE tenant_proj_001 CONNECTION LIMIT 5;
磁盘配额可通过 tablespace + 文件系统 quota 实现,但开发环境一般不需要。
用户在自己的 schema 内拥有完整的 DDL 和 DML 权限,包括:
可以做
不能做
这是必须的——否则用户开发应用时连建表都要审批,体验不可接受。
项目创建时
自动执行 CREATE SCHEMA + CREATE ROLE + GRANT
沙盒启动时
在沙盒环境变量中注入带对应 role 凭据的 DATABASE_URL
项目删除时
DROP SCHEMA ... CASCADE + DROP ROLE 彻底清理
定位:软件工厂是开发环境,不是生产环境
用户 DROP TABLE 或写 bug 删了数据,和在本地删了 SQLite 文件一样——是用户的责任。不需要提供企业级备份恢复。
pg_restore 回对应 schema-- 1. 系统 schema(仅 blade_system 可访问) CREATE SCHEMA IF NOT EXISTS system; CREATE ROLE blade_system WITH LOGIN PASSWORD '...'; GRANT ALL ON SCHEMA system TO blade_system; -- 2. 创建租户(项目创建时自动执行) CREATE SCHEMA tenant_proj_001; CREATE ROLE tenant_proj_001 WITH LOGIN PASSWORD '...'; -- 授予 schema 权限 GRANT USAGE, CREATE ON SCHEMA tenant_proj_001 TO tenant_proj_001; GRANT ALL ON ALL TABLES IN SCHEMA tenant_proj_001 TO tenant_proj_001; ALTER DEFAULT PRIVILEGES IN SCHEMA tenant_proj_001 GRANT ALL ON TABLES TO tenant_proj_001; -- 设置 search_path(用户无需写 schema 前缀) ALTER ROLE tenant_proj_001 SET search_path = tenant_proj_001, public; -- 资源限制 ALTER ROLE tenant_proj_001 SET statement_timeout = '30s'; ALTER ROLE tenant_proj_001 CONNECTION LIMIT 5; -- 撤销对 public schema 的默认 CREATE 权限(PG 15+ 默认已撤销) REVOKE CREATE ON SCHEMA public FROM tenant_proj_001; -- 3. 删除租户(项目删除时执行) DROP SCHEMA tenant_proj_001 CASCADE; DROP ROLE tenant_proj_001;