chore: initial commit of ai site platform
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
128
blueprint/platform/execution-steps.md
Normal file
128
blueprint/platform/execution-steps.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# 中台执行步骤与安全闸门
|
||||
|
||||
面向 go-zero(或等价中台)实现 `POST /api/v1/apps/{slug}:publish`。
|
||||
|
||||
## 1. 入口校验
|
||||
|
||||
1. 鉴权:用户已登录,具备 `app.admin` 或「创建应用」权限
|
||||
2. 限流:每租户每小时发布次数上限(建议 ≤ 20)
|
||||
3. Body 必须是完整 `AppBlueprint`
|
||||
4. 用 `app-blueprint.schema.json` 校验;失败直接 400
|
||||
5. `meta.slug` 与 path 中 slug 一致;租户内唯一
|
||||
|
||||
## 2. 标识符白名单(防 SQL 注入)
|
||||
|
||||
仅允许匹配:
|
||||
|
||||
```text
|
||||
^[a-z][a-z0-9_]{1,47}$
|
||||
```
|
||||
|
||||
校验对象:`slug`、`entity.name/table`、所有 `field.name`、`index.name`
|
||||
拒绝:大小写混用、连字符、空格、引号、注释符、SQL 关键字作表名(建议黑名单:`select/drop/user/...`)
|
||||
|
||||
## 3. 分配存储(用户不可指定 DSN)
|
||||
|
||||
| storage.mode | 行为 |
|
||||
|--------------|------|
|
||||
| `schema_per_app` | 平台在共享实例创建 `schema_name`(可忽略 AI 填的名字,按 `app_{tenant}_{slug}` 重写) |
|
||||
| `database_per_app` | 平台开通独立库,凭证写入 KMS/密钥服务 |
|
||||
|
||||
落库元数据示例:
|
||||
|
||||
```text
|
||||
tenant_apps(app_id, tenant_id, slug, schema_name, engine, blueprint_json, status, created_at)
|
||||
tenant_app_entities(...)
|
||||
tenant_app_fields(...)
|
||||
tenant_app_apis(...)
|
||||
```
|
||||
|
||||
## 4. 生成并执行 DDL(参数化/白名单拼接)
|
||||
|
||||
伪代码原则:
|
||||
|
||||
- 只拼已经过白名单的标识符
|
||||
- 字段类型映射用固定字典,禁止把 AI 的 type 字符串直接塞进 SQL
|
||||
|
||||
类型映射建议(Postgres):
|
||||
|
||||
| blueprint type | SQL |
|
||||
|----------------|-----|
|
||||
| string | VARCHAR(n) |
|
||||
| text | TEXT |
|
||||
| int | INTEGER |
|
||||
| bigint | BIGINT |
|
||||
| decimal | NUMERIC(p,s) |
|
||||
| boolean | BOOLEAN |
|
||||
| date | DATE |
|
||||
| datetime | TIMESTAMPTZ |
|
||||
| enum | VARCHAR(n) + CHECK |
|
||||
| json | JSONB |
|
||||
| file_ref | VARCHAR(512) |
|
||||
|
||||
每个表强制附加系统列(即使蓝图未写):
|
||||
|
||||
```sql
|
||||
tenant_id BIGINT NOT NULL,
|
||||
created_by BIGINT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
```
|
||||
|
||||
`row_policies=tenant_isolated` → 所有查询自动 `AND tenant_id = :current_tenant`。
|
||||
|
||||
## 5. 注册动态 API
|
||||
|
||||
读取 `apis.resources[]`:
|
||||
|
||||
- 在网关/服务路由表注册 path
|
||||
- `operations` 决定开放方法
|
||||
- `allowed_filters/sorts` 写入配置;运行时拒绝未声明字段
|
||||
|
||||
禁止:按请求参数动态选物理表名。
|
||||
允许:`app_slug + resource` → 元数据查出 `schema.table`。
|
||||
|
||||
## 6. 种子数据
|
||||
|
||||
若 `seed.import_excel=true`:
|
||||
|
||||
1. 从 `meta.source.excel_ref` 拉文件
|
||||
2. 按 `field.from_excel.column` 映射
|
||||
3. 行数 ≤ `seed.max_rows`
|
||||
4. 批量插入,单行失败记入 errors,不中断整单(或按策略 fail-fast)
|
||||
|
||||
## 7. 发布事务与回滚
|
||||
|
||||
建议状态机:
|
||||
|
||||
```text
|
||||
draft → validating → provisioning → importing → published
|
||||
↘ failed(保留草稿,DDL 尽量事务/可回滚)
|
||||
```
|
||||
|
||||
失败时:
|
||||
|
||||
- schema 已建:标记 `failed`,提供 `DELETE app` 清理
|
||||
- 写审计:谁、何时、哪份 blueprint hash、结果
|
||||
|
||||
## 8. 运行时读路径(列表页)
|
||||
|
||||
```text
|
||||
Auth → 解析 tenant → 查 app 元数据 → 校验 resource
|
||||
→ 校验 filter/sort 白名单 → 组装 SELECT
|
||||
→ 强制 tenant_id 条件 → 分页返回
|
||||
```
|
||||
|
||||
前端只读 blueprint 渲染,不信任客户端传来的「表名/SQL」。
|
||||
|
||||
## 9. 最小落地服务拆分
|
||||
|
||||
| 服务 | 职责 |
|
||||
|------|------|
|
||||
| `ai-generate` | 素材 → draft blueprint |
|
||||
| `app-meta` | 蓝图存储、校验、发布状态 |
|
||||
| `schema-runner` | DDL / 迁移 / 清理 |
|
||||
| `dynamic-crud` | 统一 CRUD / import / export |
|
||||
| `gateway` | 鉴权、限流、WAF、路由 |
|
||||
|
||||
首版可先 2 个进程:`ai-generate(FastAPI)` + `platform(go-zero 含 meta/runner/crud)`。
|
||||
Reference in New Issue
Block a user