chore: initial commit of ai site platform
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
27
docs/README.md
Normal file
27
docs/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# 文档目录
|
||||
|
||||
本目录为智能体「生成 / 发布 / 灌数」相关说明(中文)。
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [智能体-生成发布-能力说明.md](./智能体-生成发布-能力说明.md) | **需求 / 能力边界**(做什么、不做什么、工作流、验收) |
|
||||
| [智能体-生成发布-API.md](./智能体-生成发布-API.md) | **接口契约**(路径、请求/响应、宿主回执字段) |
|
||||
| [数据同步-中间件.md](./数据同步-中间件.md) | 跨库实时同步(SQLite/MySQL/Postgres) |
|
||||
|
||||
> 业务用语称「**模块**」。HTTP 路径仍为 `/api/v1/apps/...`。智能体默认无需配置模块白名单即可自建发布。
|
||||
|
||||
## Linux 部署
|
||||
|
||||
本仓库根目录提供 `start.sh` / `restart.sh` / `stop.sh` / `pull-and-restart.sh`。
|
||||
与宇恒 Web 合并的交互菜单见同级目录 [`../ops/README.md`](../../ops/README.md)(`./deploy-menu.sh`)。
|
||||
|
||||
**配置热重载**(改域名/Nginx/yaml 不必整栈 rebuild):[`../nginx/README.md`](../nginx/README.md),执行 `./reload-config.sh`。
|
||||
|
||||
| 改什么 | 文件 | 命令 |
|
||||
|--------|------|------|
|
||||
| 容器反代 | `web/nginx.conf` | `./reload-config.sh web` |
|
||||
| 公开 URL / 发布回执 | `.env` 的 `AIJZ_PUBLIC_BASE_URL` + `platform/etc/platform.docker.yaml` | `./reload-config.sh platform` |
|
||||
| Gateway | `gateway/etc/gateway.docker.yaml` | `./reload-config.sh gateway` |
|
||||
| LLM Key | `.env` | `./reload-config.sh ai` |
|
||||
| 供应商 / 模型列表 | `ai-service/etc/llm.yaml` | `./reload-config.sh ai` |
|
||||
| 域名 HTTPS | `nginx/aijz.host.conf` + 证书 | `./reload-config.sh host-nginx` |
|
||||
53
docs/外公司部署-授权与登录控制.md
Normal file
53
docs/外公司部署-授权与登录控制.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# 登录策略与外公司部署授权
|
||||
|
||||
## 删文件后旧包还能用吗?
|
||||
|
||||
分几层:
|
||||
|
||||
| 客户删了什么 | 能否拦住旧延期包 |
|
||||
|--------------|------------------|
|
||||
| 只删 `leases/*.json` | **能** — 消费记录在 `state/_consumed.json` |
|
||||
| 只删 leases + 改/清 state 文件 | **能**(有库时)— Postgres `license_consumed` 双写,可恢复 |
|
||||
| **leases + state + 数据库全删** | 本地拦不住 → 需配置 **`RedeemURL` 联网核销**,或你们**永不重签同一 id** |
|
||||
|
||||
纯离线、客户把机器数据全部清空,没有任何方案能 100% 防复用(等于新装机)。要硬保证:配核销服务,或只发一次性 id 且服务端登记。
|
||||
|
||||
---
|
||||
|
||||
## 推荐:延期软件 + 分层持久化
|
||||
|
||||
```text
|
||||
./data/license/leases/ # 租约文件(可删)
|
||||
./data/license/state/ # _consumed.json 已消费 id(签名)
|
||||
Postgres license_consumed # 第二副本
|
||||
RedeemURL(可选) # 你们服务端核销 id
|
||||
```
|
||||
|
||||
### yaml
|
||||
|
||||
```yaml
|
||||
License:
|
||||
Enabled: true
|
||||
Customer: "A公司"
|
||||
LeaseDir: "./data/license/leases"
|
||||
StateDir: "./data/license/state"
|
||||
ControlSecret: "换成强密钥"
|
||||
RedeemURL: "https://license.你们的域名" # 建议生产打开
|
||||
SeedNotAfter: "2027-07-30"
|
||||
```
|
||||
|
||||
`RedeemURL` 时:导入包会 `POST {RedeemURL}/v1/license/redeem`,服务端若该 id 已核销则拒绝。删光客户机数据后旧包仍无效。
|
||||
|
||||
临时延期:**仅 1 次**、最多 30 天。同一本地 id 不可二次导入。
|
||||
|
||||
---
|
||||
|
||||
## API
|
||||
|
||||
`X-License-Secret`:`renew` / `extend` / `import`
|
||||
|
||||
```bash
|
||||
curl -X POST http://客户机:8888/api/v1/license/import \
|
||||
-H "X-License-Secret: 强密钥" -H "Content-Type: application/json" \
|
||||
--data-binary @pack.json
|
||||
```
|
||||
100
docs/数据同步-中间件.md
Normal file
100
docs/数据同步-中间件.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# 跨库数据同步中间件
|
||||
|
||||
支持 **SQLite ↔ MySQL ↔ Postgres**,不要求两端同一种数据库。变更经 **outbox 队列** 近实时投递;冲突进 **冲突队列**。
|
||||
|
||||
## 权限与隔离
|
||||
|
||||
| 项 | 说明 |
|
||||
|----|------|
|
||||
| 谁可配 | 仅公司**顶级权限(管理员)**,权限名「数据同步」 |
|
||||
| 谁不可 | 编辑 / 只读、智能体账号(即使有「发布模块」) |
|
||||
| 数据隔离 | 通道与冲突带 `tenant_id`;公司 A 看不到公司 B 的通道/DSN |
|
||||
| 多服务器 | 同一公司可建多条通道,分别填 B、C 等库的 DSN |
|
||||
|
||||
## 典型场景:A / B / C
|
||||
|
||||
| 端 | 角色 |
|
||||
|----|------|
|
||||
| **A** | 线上库(用户增删改) |
|
||||
| **B** | 本地库(本机业务 + 接收 C) |
|
||||
| **C** | 额外数据源(Excel / API / 导入),只写入 **B** |
|
||||
|
||||
推荐配置:
|
||||
|
||||
1. 建一条通道:`local` = B,`remote` = A,**方向 `bidirectional`**,冲突策略 `queue`(或 LWW)。
|
||||
2. C 的数据用 **ingest API**(或业务直接写 B)写入本地;触发器进 outbox,再推到 A。
|
||||
3. A 上用户改的数据经 outbox 拉回 B。
|
||||
4. 怀疑漏数时点 **对账**,或等双向通道约每分钟自动对账。
|
||||
|
||||
如何保证**不漏、不多**:
|
||||
|
||||
| 手段 | 防什么 |
|
||||
|------|--------|
|
||||
| 表触发器 → `_ajz_sync_outbox` | 漏(本地/线上变更必入队) |
|
||||
| 应用远端时 `WithApplying`(触发器不写 outbox) | 多(A↔B 回声环) |
|
||||
| 目标 meta 版本相等则跳过 | 多(重复投递) |
|
||||
| 目标版本更新 → 冲突队列 / LWW | 并发改同一行 |
|
||||
| 主键对账 reconcile | 漏(存量差、触发器未装前的行) |
|
||||
| C→B upsert 同主键 | 多(重复灌入) |
|
||||
|
||||
```
|
||||
C ──ingest/写库──► B (local) ◄──bidirectional outbox──► A (remote)
|
||||
```
|
||||
|
||||
## 能力
|
||||
|
||||
| 项 | 说明 |
|
||||
|----|------|
|
||||
| 方言 | `sqlite` / `mysql` / `postgres` |
|
||||
| 实时性 | 表触发器写 `_ajz_sync_outbox`,worker 默认每 500ms 拉取 |
|
||||
| 方向 | 本地→线上 / 线上→本地 / **双向**(A↔B 场景用这个) |
|
||||
| 冲突 | `queue`(入队)/ `lww_source` / `lww_target` |
|
||||
| 对账 | `POST .../reconcile`;双向运行中约每分钟自动一次 |
|
||||
| 外部源 | `POST .../ingest`:C → B,再同步到 A |
|
||||
| 配置 | 控制台「数据同步」页;可改线上 DSN |
|
||||
|
||||
配置与冲突持久化:`data/dbsync/channels.json`、`conflicts.json`(Docker:`.runtime/dbsync`)。
|
||||
|
||||
## 控制台用法
|
||||
|
||||
1. 登录 → **数据同步** → **新建通道**
|
||||
2. 本地 B:如 `sqlite` + `file:./data/local.db`,表名逗号分隔
|
||||
3. 线上 A:`mysql` + `user:pass@tcp(host:3306)/db?parseTime=true`
|
||||
4. 方向选 **双向** → **测试连接** → **保存** → **启动**
|
||||
5. 需要补漏时点 **对账**;C 数据走业务写 B 或调用 ingest API
|
||||
|
||||
## API(需公司顶级权限「数据同步」/ 管理员)
|
||||
|
||||
| 方法 | 路径 |
|
||||
|------|------|
|
||||
| GET/POST | `/api/v1/admin/sync/channels` |
|
||||
| GET/PUT/DELETE | `/api/v1/admin/sync/channels/{id}` |
|
||||
| POST | `/api/v1/admin/sync/test` |
|
||||
| POST | `/api/v1/admin/sync/channels/{id}/prepare\|start\|stop` |
|
||||
| POST | `/api/v1/admin/sync/channels/{id}/reconcile` |
|
||||
| POST | `/api/v1/admin/sync/channels/{id}/ingest` |
|
||||
| GET | `/api/v1/admin/sync/conflicts` |
|
||||
| POST | `/api/v1/admin/sync/conflicts/{id}/resolve` |
|
||||
|
||||
### ingest 示例
|
||||
|
||||
```json
|
||||
POST /api/v1/admin/sync/channels/{id}/ingest
|
||||
{
|
||||
"table": "article",
|
||||
"source": "excel",
|
||||
"rows": [
|
||||
{ "id": "c-001", "title": "来自 C" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
按主键 upsert 写入本地 B,触发器入 outbox,worker 再推到线上 A。
|
||||
|
||||
## 注意
|
||||
|
||||
- 两端业务表结构需兼容(同名列);主键默认 `id`,可用 `pk_columns` 覆盖。
|
||||
- MySQL 需账号有建触发器权限。
|
||||
- 密钥在 DSN 中;列表页会打码显示。
|
||||
- 「实时」为亚秒级轮询 + 触发器,非 MySQL binlog CDC;同机延迟通常 <1s。
|
||||
- 对账按**主键集合**补缺行,不做逐字段内容 diff;同 PK 内容冲突仍靠版本 / 冲突队列。
|
||||
450
docs/智能体-生成发布-API.md
Normal file
450
docs/智能体-生成发布-API.md
Normal file
@@ -0,0 +1,450 @@
|
||||
# 智能体 · 生成与发布 API
|
||||
|
||||
Base URL:`http://127.0.0.1:8180`(网关)
|
||||
|
||||
需求 / 能力说明见:[智能体-生成发布-能力说明.md](./智能体-生成发布-能力说明.md)
|
||||
|
||||
> 业务用语:**模块**。API 路径仍为 `/api/v1/apps/...`。
|
||||
> **智能体默认无需配置 `app_slugs`**:启用「生成发布」后可自由发布自建模块;`app_slugs` 仅在需要白名单限制时填写。
|
||||
> **禁止**在已发布模块的业务库查用户 / 权限。账号绑定只走「首次登记」。
|
||||
|
||||
---
|
||||
|
||||
## 总览
|
||||
|
||||
| 步骤 | 方法 | 路径 | 鉴权 |
|
||||
|------|------|------|------|
|
||||
| 首次登记 | POST | `/api/v1/auth/agent/register` | 公开 + `register_secret` |
|
||||
| 换票 | POST | `/api/v1/auth/token` | 公开(client_credentials) |
|
||||
| 列模块 | GET | `/api/v1/apps` | Bearer + 「读取模块」(管理=全部;智能体默认不限制) |
|
||||
| 登记在建 | PUT | `/api/v1/apps/{slug}/draft` | Bearer + 「发布模块」 |
|
||||
| 读蓝图 | GET | `/api/v1/apps/{slug}/blueprint` | Bearer + 「读取模块」 |
|
||||
| 列模型 | GET | `/ai/api/v1/llm/providers` | 公开 |
|
||||
| 生成 | POST | `/api/v1/apps/generate` | 网关可公开 |
|
||||
| 发布 | POST | `/api/v1/apps/{slug}/publish` | Bearer + 「发布模块」 |
|
||||
| 公开读(加密路径) | GET | `/api/v1/public/m/{token}/blueprint` | 公开 |
|
||||
| 导入 | POST | `/api/v1/apps/{slug}/{resource}/import` | Bearer + `row.import` |
|
||||
| 抽查 | GET | `/api/v1/apps/{slug}/{resource}` | Bearer + `row.read` |
|
||||
|
||||
决策树:
|
||||
|
||||
```text
|
||||
GET /apps(本账号可见模块)
|
||||
├─ 选中已有模块 slug
|
||||
│ → GET blueprint(避开已有 page id/route)
|
||||
│ → generate(生成新页面)
|
||||
│ → publish mode=add_pages|auto
|
||||
│ → import
|
||||
└─ 无合适模块
|
||||
→ generate(完整多页蓝图)
|
||||
→ publish mode=create|auto(自定新 slug,无需预授权)
|
||||
→ import
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 0. 首次登记
|
||||
|
||||
`POST /api/v1/auth/agent/register`(公开)
|
||||
|
||||
宿主第一次接入时调用。必须上传:
|
||||
|
||||
| 宿主侧 | API 字段 | 必填 | 说明 |
|
||||
|--------|----------|------|------|
|
||||
| 宇恒 ID | `host_key` | 是 | 稳定唯一标识,幂等绑定 |
|
||||
| 名称 | `name` | 是 | 控制台显示名 |
|
||||
| — | `tenant_id` | 否 | 默认 `1` |
|
||||
| — | `register_secret` | 是 | 与平台注册密钥一致 |
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "宇恒节点显示名",
|
||||
"host_key": "<宇恒ID>",
|
||||
"tenant_id": 1,
|
||||
"register_secret": "dev-only-change-me"
|
||||
}
|
||||
```
|
||||
|
||||
响应含 `client_id` / `client_secret`(只返回一次),`status` 为 `pending`。
|
||||
管理员在控制台选角色「生成发布」并启用后即可换票。**可访问模块可留空**(留空=可自由发布自建模块)。
|
||||
|
||||
同一 `host_key`:pending 重连会轮换 secret;已 active 再 register → 409。
|
||||
|
||||
---
|
||||
|
||||
## 1. 换票
|
||||
|
||||
`POST /api/v1/auth/token`(公开)
|
||||
|
||||
```json
|
||||
{
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": "agt_xxx",
|
||||
"client_secret": "明文密钥"
|
||||
}
|
||||
```
|
||||
|
||||
取 `access_token`。后续列模块 / 读蓝图 / 发布 / 导入须:
|
||||
|
||||
`Authorization: Bearer <access_token>`
|
||||
|
||||
### 权限与模块授权
|
||||
|
||||
| 权限 | 用途 |
|
||||
|------|------|
|
||||
| 「发布模块」 | 发布模块(必选) |
|
||||
| 「读取模块」 | 列模块、读蓝图(必选) |
|
||||
| `row.import` | 灌数(必选) |
|
||||
| `row.read` | 抽查(建议) |
|
||||
| `storage.write` / `storage.read` | 素材(建议) |
|
||||
|
||||
推荐角色:**生成发布(`publisher`)**。
|
||||
|
||||
`app_slugs`:**可选白名单**。
|
||||
- **留空(推荐默认)**:不限制,智能体可自定 slug 生成/发布
|
||||
- 填写若干 slug 或 `*`:仅允许列表内(`*`=全部)
|
||||
|
||||
生成接口经网关可公开;发布与导入须鉴权(角色权限),**不强制**后台预授权模块。
|
||||
|
||||
---
|
||||
|
||||
## 2. 列出模块(先选目标)
|
||||
|
||||
`GET /api/v1/apps`
|
||||
需 Bearer + 「读取模块」。
|
||||
|
||||
| 调用方 | 可见范围(`scope`) |
|
||||
|--------|---------------------|
|
||||
| 管理账号(非 agent) | `all`:本租户全部(含在建) |
|
||||
| 智能体(`app_slugs` 空或含 `*`) | `open`:不限制 |
|
||||
| 智能体(配置了白名单) | `granted`:仅白名单 |
|
||||
|
||||
```bash
|
||||
curl -s http://127.0.0.1:8180/api/v1/apps \
|
||||
-H "Authorization: Bearer <access_token>"
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"scope": "all",
|
||||
"items": [
|
||||
{
|
||||
"app_id": "...",
|
||||
"slug": "settlement",
|
||||
"name": "沉降观测",
|
||||
"status": "draft",
|
||||
"status_label": "在建",
|
||||
"building": true,
|
||||
"page_count": 4,
|
||||
"entity_count": 2,
|
||||
"updated_at": "2026-07-24T08:00:00Z",
|
||||
"created_at": "2026-07-24T08:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| 情况 | 下一步 |
|
||||
|------|--------|
|
||||
| 有目标模块(含在建) | 记下 `slug` → 读蓝图 / 继续生成 → `publish` |
|
||||
| 没有 | 选定新 `slug` → generate → `PUT .../draft` 登记在建 → `publish` 上线 |
|
||||
|
||||
### 2.1 登记在建模块
|
||||
|
||||
生成蓝图后、正式发布前:
|
||||
|
||||
`PUT /api/v1/apps/{slug}/draft`
|
||||
Body:`{ "blueprint": { ... } }`
|
||||
需 「发布模块」。不跑 DDL;状态为 `draft`(在建)。已发布模块不可用本接口覆盖。
|
||||
|
||||
---
|
||||
|
||||
## 3. 读取已发布/在建蓝图
|
||||
|
||||
`GET /api/v1/apps/{slug}/blueprint`
|
||||
需 Bearer + 「读取模块」 + 该模块已授权。
|
||||
|
||||
用途:
|
||||
|
||||
- 生成新页面前,收集已有 `pages[].id` / `route`,避免冲突
|
||||
- 发布后自检
|
||||
|
||||
---
|
||||
|
||||
## 4. 列出大模型(可选)
|
||||
|
||||
`GET /ai/api/v1/llm/providers`(公开)
|
||||
兼容:`http://127.0.0.1:8180/ai/api/v1/llm/providers`
|
||||
|
||||
```json
|
||||
{
|
||||
"default": "deepseek",
|
||||
"providers": [
|
||||
{
|
||||
"id": "deepseek",
|
||||
"label": "DeepSeek",
|
||||
"configured": true,
|
||||
"default_model": "deepseek-chat",
|
||||
"models": [{ "id": "deepseek-chat", "label": "deepseek-chat" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 生成蓝图 / 生成新页面
|
||||
|
||||
`POST /api/v1/apps/generate`
|
||||
(网关转发 AI;兼容 `POST /ai/api/v1/apps/generate`)
|
||||
|
||||
`Content-Type: multipart/form-data`
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `prompt` | string | 建议 | 需求描述。**已有模块**时写清:目标 slug、要新增哪些页面、勿复用已有 id/route |
|
||||
| `storage_mode` | string | 否 | `schema_per_app`(默认)或 `database_per_app` |
|
||||
| `llm_provider` | string | 否 | 默认 `deepseek` |
|
||||
| `llm_model` | string | 否 | 空则用厂商默认 |
|
||||
| `excel` | file | 否 | xlsx / csv / json |
|
||||
| `data_file` | file | 否 | 同 excel |
|
||||
| `images` | file[] | 否 | 界面截图 |
|
||||
| `layout_files` | file[] | 否 | 页面 HTML/MHTML |
|
||||
|
||||
```bash
|
||||
# 示例:为已有模块生成新页面
|
||||
curl -s http://127.0.0.1:8180/api/v1/apps/generate \
|
||||
-F "prompt=目标模块 settlement。已有 page id: dash_main, list_records。请新生成「测点筛选」列表+新建表单,id/route 勿冲突。" \
|
||||
-F "storage_mode=schema_per_app" \
|
||||
-F "llm_provider=deepseek" \
|
||||
-F "llm_model=deepseek-chat" \
|
||||
-F "excel=@./settlement.xlsx" \
|
||||
-F "images=@./board_a.png"
|
||||
```
|
||||
|
||||
成功响应要点:
|
||||
|
||||
```json
|
||||
{
|
||||
"draft": {
|
||||
"version": "1.0",
|
||||
"meta": { "slug": "settlement", "name": "..." },
|
||||
"entities": [],
|
||||
"apis": {},
|
||||
"pages": [],
|
||||
"storage": {},
|
||||
"security": {}
|
||||
},
|
||||
"warnings": [],
|
||||
"confidence": 0.86,
|
||||
"require_confirm": true,
|
||||
"llm_provider": "deepseek",
|
||||
"llm_model": "deepseek-chat",
|
||||
"fidelity": { "skipped": false, "target": 95, "final_score": 96, "passed": true },
|
||||
"generate_log": { "run_id": "...", "lines": [] }
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `draft` | 蓝图;发布时提交(可微调) |
|
||||
| `draft.meta.slug` | 新建模块时用此 slug;已有模块发布时以路径 `{slug}` 为准 |
|
||||
| `draft.pages` | **禁止只生成 1 个 page**;数量不设上限 |
|
||||
| `draft == null` | 生成失败,看 `warnings` / `generate_log` |
|
||||
|
||||
### 页面约定
|
||||
|
||||
| type | 用途 |
|
||||
|------|------|
|
||||
| `list` | 列表(建议 `actions` 含 `import`) |
|
||||
| `form_create` | 新建表单 |
|
||||
| `form_edit` | 编辑表单 |
|
||||
| `dashboard` | 看板 |
|
||||
| `detail` | 详情 |
|
||||
|
||||
每个 page 必须有独立 `id` / `title` / `route` / `entity`。
|
||||
|
||||
```json
|
||||
"layout": {
|
||||
"columns": ["sku", "qty", "status"],
|
||||
"actions": ["create", "edit", "delete", "export", "import", "refresh"]
|
||||
}
|
||||
```
|
||||
|
||||
**已有模块**:`draft` 应主要是**新生成的 pages**(及对应 entities / apis),不要把旧页面再写一遍。
|
||||
**新建模块**:`draft` 为完整多页蓝图。
|
||||
|
||||
---
|
||||
|
||||
## 6. 发布(宿主 → 建站平台)
|
||||
|
||||
宿主(宇恒)侧「发布」应把建站蓝图与展示元数据 **POST 到本建站平台**;平台落库建站,并**按用户/智能体 ID 加密出文件路径**,回执给宿主表格展示。
|
||||
|
||||
`POST /api/v1/apps/{slug}/publish`
|
||||
|
||||
Headers:
|
||||
|
||||
- `Authorization: Bearer <access_token>`
|
||||
- `Content-Type: application/json`
|
||||
|
||||
Path `{slug}` = 选定的目标**模块**(新建时为新 slug)。`blueprint.meta.slug` 会对齐到路径 slug。
|
||||
默认无需预授权;仅当账号配置了 `app_slugs` 白名单时才校验。
|
||||
|
||||
```json
|
||||
{
|
||||
"mode": "auto",
|
||||
"blueprint": { },
|
||||
"host_meta": {
|
||||
"module_name": "whm123",
|
||||
"publish_style": "immediate",
|
||||
"host_base_url": "https://whm123.yuheng.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `mode` | 见下表 |
|
||||
| `blueprint` | 建站蓝图(必填) |
|
||||
| `host_meta.module_name` | 宿主表格「模块名称」 |
|
||||
| `host_meta.publish_style` | `immediate` → 立即发布上线 |
|
||||
| `host_meta.host_base_url` | 宿主访问域名;有则作为回执 `access_url` |
|
||||
|
||||
| `mode` | 含义 |
|
||||
|--------|------|
|
||||
| `auto`(默认) | 模块已存在 → 发布新生成的页面;不存在 → 新建模块 |
|
||||
| `add_pages` | 必须已存在;发布草稿中的**新页面** |
|
||||
| `create` | 必须不存在;新建模块 |
|
||||
| `replace` | 整份覆盖(慎用) |
|
||||
|
||||
日常用 `auto` 或显式 `add_pages` / `create`。
|
||||
|
||||
### 加密访问路径
|
||||
|
||||
平台用当前账号的 **用户/智能体 ID(owner_id)** + 租户 + 模块 slug,加密生成逻辑文件路径:
|
||||
|
||||
- `access_path`:如 `m/ajzm1_...`(路径中**无明文 slug / 用户 id**)
|
||||
- `access_url`:优先宿主 `host_base_url`;否则 `{PublicBaseURL}/api/v1/public/{access_path}/blueprint`
|
||||
|
||||
公开读取蓝图(无需登录):
|
||||
|
||||
`GET /api/v1/public/m/{token}/blueprint`
|
||||
其中 `{token}` 为 `access_path` 去掉前缀 `m/` 的段。
|
||||
|
||||
### 宿主「AI 表格数据」字段映射
|
||||
|
||||
| 宿主表格 | 取自发布响应 |
|
||||
|----------|----------------|
|
||||
| 模块名称 | `module_name` |
|
||||
| 发布方式 | `publish_style`(`immediate` → 立即发布上线) |
|
||||
| 访问地址 | `access_url`(或宿主自拼域名 + `access_path`) |
|
||||
| 发布时间 | `published_at` |
|
||||
| 状态 | `status` = `published` → 已发布 |
|
||||
|
||||
下一步仍是:**灌数 → 打开模块**。
|
||||
|
||||
### 已有模块(`auto` / `add_pages`)
|
||||
|
||||
- 保留该模块已有 pages / entities / apis
|
||||
- 发布草稿中**新生成**的 page(`id`、`route` 不可冲突)
|
||||
- 新 entity / resource 一并加入;已有 entity 只追加新字段
|
||||
- 若没有任何新 page / entity / resource → 400
|
||||
|
||||
### 新建模块时 blueprint 至少含
|
||||
|
||||
- `meta.slug` / `meta.name`
|
||||
- `version`(如 `"1.0"`)
|
||||
- `storage`:`{ "mode": "schema_per_app", "engine": "postgres" }`
|
||||
- `security`:`{ "visibility": "private", "roles": [], "row_policies": [] }`
|
||||
- `apis.base_path` = `/api/v1/apps/{slug}`
|
||||
- `entities` / `apis` / `pages`
|
||||
|
||||
```bash
|
||||
curl -s http://127.0.0.1:8180/api/v1/apps/settlement/publish \
|
||||
-H "Authorization: Bearer <access_token>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"mode":"create","host_meta":{"module_name":"whm123","publish_style":"immediate","host_base_url":"https://whm123.yuheng.com"},"blueprint":{...}}'
|
||||
```
|
||||
|
||||
响应示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"app_id": "...",
|
||||
"slug": "settlement",
|
||||
"schema_name": "app_t1_settlement",
|
||||
"status": "published",
|
||||
"publish_mode": "created",
|
||||
"module_name": "whm123",
|
||||
"publish_style": "immediate",
|
||||
"access_path": "m/ajzm1_...",
|
||||
"access_url": "https://whm123.yuheng.com",
|
||||
"published_at": "2026-07-24T02:00:00Z",
|
||||
"owner_id": 3,
|
||||
"endpoints": ["GET /api/v1/apps/settlement/blueprint", "..."],
|
||||
"ddl": [],
|
||||
"memory_mode": false
|
||||
}
|
||||
```
|
||||
|
||||
| `publish_mode` | 含义 |
|
||||
|----------------|------|
|
||||
| `created` | 新建了模块 |
|
||||
| `pages_added` | 向已有模块发布了新页面 |
|
||||
| `replaced` | 整份覆盖 |
|
||||
|
||||
| HTTP | 原因 |
|
||||
|------|------|
|
||||
| 401 | token 无效 |
|
||||
| 403 | 缺 「发布模块」;或配置了白名单但不含该 slug |
|
||||
| 400 | 蓝图非法 / page id 冲突 / mode 与是否存在不一致 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 导入业务数据(发布后必做)
|
||||
|
||||
发布只建表,**不自动灌数**。
|
||||
|
||||
`POST /api/v1/apps/{slug}/{resource}/import`
|
||||
`Content-Type: multipart/form-data`
|
||||
需 Bearer + `row.import` + 模块授权。
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `file` | file | 是 | xlsx / csv / json |
|
||||
|
||||
`resource` = `apis.resources[].path`(无前导 `/`),如 `records`。
|
||||
|
||||
```bash
|
||||
curl -s "http://127.0.0.1:8180/api/v1/apps/settlement/records/import" \
|
||||
-H "Authorization: Bearer <access_token>" \
|
||||
-F "file=@./settlement.xlsx"
|
||||
```
|
||||
|
||||
```json
|
||||
{ "inserted": 120, "skipped": 0, "errors": [] }
|
||||
```
|
||||
|
||||
抽查:
|
||||
|
||||
`GET /api/v1/apps/{slug}/{resource}?page=1&page_size=5`(需 `row.read`)
|
||||
确认 `total > 0`,否则任务未完成。
|
||||
|
||||
---
|
||||
|
||||
## 8. 推荐调用顺序
|
||||
|
||||
```text
|
||||
0. POST /api/v1/auth/agent/register 宇恒ID(host_key) + 名称(name)
|
||||
1. (管理员)启用 + 角色 publisher(模块白名单可选,默认留空)
|
||||
2. POST /api/v1/auth/token
|
||||
3. GET /api/v1/apps 先选模块(仅本账号可见)
|
||||
4. GET /api/v1/apps/{slug}/blueprint 仅已有模块:避让已有 page
|
||||
5. POST /api/v1/apps/generate 生成新页面 或 完整蓝图
|
||||
6. POST /api/v1/apps/{slug}/publish mode=auto | add_pages | create
|
||||
7. POST /api/v1/apps/{slug}/{resource}/import
|
||||
8. GET /api/v1/apps/{slug}/{resource}?page=1&page_size=5
|
||||
```
|
||||
|
||||
不要:查业务库用户表;行级增删改(除 import);admin/audit;对已有模块默认 `replace`。
|
||||
语义:已有模块上是 **生成新页面再发布**;新建模块自定 slug 即可,无需后台预授权。
|
||||
185
docs/智能体-生成发布-能力说明.md
Normal file
185
docs/智能体-生成发布-能力说明.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# 智能体能力说明:生成、发布与灌数
|
||||
|
||||
一类专用智能体:先选定**模块**,再生成页面并发布到建站平台,最后导入业务数据。
|
||||
接口细节见:[智能体-生成发布-API.md](./智能体-生成发布-API.md)
|
||||
|
||||
> 业务用语称「**模块**」(API 路径仍为 `/apps`,字段仍为 `app_slugs`)。
|
||||
> **管理账号**可查看本租户全部模块(含在建)。
|
||||
> **智能体**:启用并赋予「生成发布」后即可**自由发布自建模块**;`app_slugs` 留空表示不限制,无需后台逐个授权。
|
||||
|
||||
---
|
||||
|
||||
## 1. 一句话定位
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| 做什么 | 登记账号 → 选模块 → **生成页面** → **向建站平台发布** → 导入数据 |
|
||||
| 得到什么 | 发布回执含模块名、加密访问路径、状态;控制台「打开模块」见多页业务后台 |
|
||||
| 管理侧 | 管理账号在「模块管理」看到全部模块(在建 / 已发布 / 失败) |
|
||||
| 不做什么 | 查业务库用户表;角色 / 邀请 / 组织管理;行级增删改(仅允许 import + 只读抽查) |
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心规则(必读)
|
||||
|
||||
### 2.1 绑定宇恒 ID(首次必做)
|
||||
|
||||
智能体账号**不在**已发布模块的业务表里。禁止在业务库翻用户 / 权限。
|
||||
|
||||
| 宿主侧 | API 字段 | 说明 |
|
||||
|--------|----------|------|
|
||||
| **宇恒 ID** | `host_key` | 稳定唯一标识;**必传** |
|
||||
| **名称** | `name` | 控制台显示名;**必传** |
|
||||
|
||||
`POST /api/v1/auth/agent/register` → `pending` → 管理员赋「生成发布」并**启用** → 换票。
|
||||
**不要求**再填写「可访问模块」才能发布。
|
||||
|
||||
### 2.2 管理账号与模块可见范围
|
||||
|
||||
| 账号类型 | `GET /api/v1/apps` 可见范围 |
|
||||
|----------|------------------------------|
|
||||
| **管理账号**(如 demo/`owner`,非 agent) | 本租户**全部**模块,含 **在建** 与已发布、失败 |
|
||||
| **智能体(`app_slugs` 为空或含 `*`)** | 不限制(`scope=open`),可列本租户模块并自由发布自建 slug |
|
||||
| **智能体(配置了白名单)** | 仅白名单内(`scope=granted`)——可选限制,非默认 |
|
||||
|
||||
状态展示:
|
||||
|
||||
| status | 中文 | 说明 |
|
||||
|--------|------|------|
|
||||
| `draft` / `validating` / `provisioning` | **在建** | 已生成蓝图或正在发布,尚未成功上线 |
|
||||
| `published` | 已发布 | 可打开业务页、可灌数 |
|
||||
| `failed` | 失败 | 发布失败,可继续编辑后重发 |
|
||||
|
||||
生成蓝图成功后可 `PUT /api/v1/apps/{slug}/draft` 登记为在建。
|
||||
|
||||
### 2.3 先选模块,再生成
|
||||
|
||||
发布前建议 `GET /api/v1/apps` 查看已有模块:
|
||||
|
||||
| 选择 | 含义 |
|
||||
|------|------|
|
||||
| **已有模块** | 为该模块 **生成新的页面**,再发布到该模块 |
|
||||
| **没有合适模块** | **生成完整多页蓝图**,再 **新建模块**(自定 slug,无需后台预授权) |
|
||||
|
||||
### 2.4 页面必须多页
|
||||
|
||||
一次生成应产出多个 `pages`(至少列表 + 新建表单;建议再加编辑 / 看板)。
|
||||
页面数量**不设上限**。列表页建议带 `import`。
|
||||
|
||||
### 2.5 发布 = 向建站平台送建站数据
|
||||
|
||||
宿主侧点击「发布」时,应把蓝图与展示元数据 **POST 到本建站平台**(不是只在宿主本地落库)。
|
||||
|
||||
平台会:
|
||||
|
||||
1. 校验并落库模块蓝图(新建或向已有模块发布新页面)
|
||||
2. **按当前用户 / 智能体 ID 加密生成访问文件路径**(`access_path`)
|
||||
3. 回执模块名称、发布方式、访问地址、发布时间、状态,供宿主「AI 表格数据」展示
|
||||
|
||||
### 2.6 发布后必须灌数
|
||||
|
||||
发布只建结构,**不会自动灌 Excel**。成功后必须 `import`,并建议抽查 `total > 0`。
|
||||
宿主提示「下一步:灌数 → 打开模块」与此一致。
|
||||
|
||||
---
|
||||
|
||||
## 3. 首次接入流程
|
||||
|
||||
```text
|
||||
宇恒 ID + 名称
|
||||
→ POST /api/v1/auth/agent/register
|
||||
→ pending
|
||||
→ 管理员:角色「生成发布」+ 启用(可访问模块可留空)
|
||||
→ 换票后即可自定 slug 生成/发布
|
||||
```
|
||||
|
||||
`app_slugs` **默认留空即可自由发布**;仅在需要收紧范围时再配白名单。
|
||||
|
||||
---
|
||||
|
||||
## 4. 能力边界
|
||||
|
||||
### 允许
|
||||
|
||||
1. 首次登记(宇恒 ID + 名称)
|
||||
2. 换票
|
||||
3. 列出本账号可访问模块、读取已发布蓝图
|
||||
4. 生成蓝图 / 生成新页面(可带 Excel / 截图 / HTML)
|
||||
5. 发布到建站平台(新建模块或向已有模块发布新页面;拿加密路径回执)
|
||||
6. 导入数据 + 只读抽查列表
|
||||
|
||||
### 禁止
|
||||
|
||||
- 业务库查用户 / 权限表
|
||||
- `row.create` / `row.update` / `row.delete`(除 import)
|
||||
- admin / audit 等管理接口
|
||||
- 对已有模块默认 `mode=replace` 整站覆盖
|
||||
- 访问未授权模块(仅当管理员配置了 `app_slugs` 白名单时才受限)
|
||||
|
||||
---
|
||||
|
||||
## 5. 角色与模块授权
|
||||
|
||||
推荐角色:**生成发布(`publisher`)**
|
||||
|
||||
| 权限 | 用途 |
|
||||
|------|------|
|
||||
| 「发布模块」 | 发布模块 |
|
||||
| `app.read` | 列模块 / 读蓝图 |
|
||||
| `row.import` | 灌数 |
|
||||
| `row.read` | 抽查 |
|
||||
| `storage.write` / `storage.read` | 素材(建议) |
|
||||
|
||||
`app_slugs`:**可选**。留空 = 不限制,智能体可随意发布自建模块;填写后才按白名单限制。
|
||||
|
||||
---
|
||||
|
||||
## 6. 宿主发布回执(需求)
|
||||
|
||||
宿主「AI 表格数据」应展示建站平台发布回执,而不是本地假数据:
|
||||
|
||||
| 表格项 | 含义 | 来自发布响应 |
|
||||
|--------|------|----------------|
|
||||
| 模块名称 | 业务显示名 | `module_name` |
|
||||
| 发布方式 | 如立即发布上线 | `publish_style`(`immediate`) |
|
||||
| 访问地址 | 可打开的地址 | `access_url`(或宿主域名 + `access_path`) |
|
||||
| 发布时间 | 平台落库时间 | `published_at` |
|
||||
| 状态 | 已发布 | `status` = `published` |
|
||||
|
||||
加密路径规则:
|
||||
|
||||
- 输入:租户 ID + 用户/智能体 ID + 模块 slug
|
||||
- 输出:`access_path`(如 `m/ajzm1_...`),路径中**无明文用户 id / slug**
|
||||
- 公开读蓝图:`GET /api/v1/public/m/{token}/blueprint`
|
||||
|
||||
---
|
||||
|
||||
## 7. 标准工作流
|
||||
|
||||
```text
|
||||
宇恒ID + 名称
|
||||
→ register → 管理员启用(publisher;模块白名单可选)
|
||||
→ 换票
|
||||
→ GET /apps 【先选模块】
|
||||
├─ 已有 → GET blueprint → generate【生成新页面】→ publish(add_pages|auto)
|
||||
└─ 没有 → generate【完整蓝图】→ publish(create|auto)【新建模块】
|
||||
→ 宿主用回执展示「AI 表格数据」(含加密访问路径)
|
||||
→ import → 抽查 total > 0 → 打开模块
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 验收清单
|
||||
|
||||
- [ ] 管理账号可在「模块管理」看到全部模块(含在建)
|
||||
- [ ] register 传了宇恒 ID + 名称
|
||||
- [ ] 角色为「生成发布」
|
||||
- [ ] 发布前 `GET /api/v1/apps` 选目标(仅见本账号模块)
|
||||
- [ ] 已有模块:generate **生成新页面**再发布;无模块才新建
|
||||
- [ ] 新页面 `id` / `route` 不与已有冲突
|
||||
- [ ] `pages` ≥ 2(含 list,建议带 import)
|
||||
- [ ] publish 回执含 `access_path` / `access_url` / `published_at` / `status`
|
||||
- [ ] 宿主表格用回执字段,不写死假地址
|
||||
- [ ] generate → publish → import 成功,列表 `total > 0`
|
||||
- [ ] 「打开模块」可见多页导航
|
||||
- [ ] 不会去业务库查用户表
|
||||
69
docs/角色说明.md
Normal file
69
docs/角色说明.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# 角色说明
|
||||
|
||||
权限与角色均使用**中文命名**。分两类:公司成员角色(登录账号)、智能体角色(机器账号)。
|
||||
|
||||
## 〇、平台超级管理员与权限收窄
|
||||
|
||||
| 层级 | 谁 | 做什么 |
|
||||
|------|----|--------|
|
||||
| 权限模块 | **超级管理员** | 管理全部权限模块;决定每个公司**拥有哪些权限** |
|
||||
| 公司一级 | **超级管理员** | 平台工作台:新建/改名公司、权限额度、管理员邀请 |
|
||||
| 打开某公司 | **超级管理员** | 「管理该公司」打开该公司内部视图;**身份仍是超管**,写操作需两次确认 |
|
||||
| 公司内日常 | **公司管理员** | 额度内分配角色/智能体;**成员管理**(如 demo 属于「演示公司」) |
|
||||
| 硬边界 | 系统 | 公司账号不能分配或调用未授予的权限;控制台 Tab 按额度显隐 |
|
||||
|
||||
默认账号:**ljk_admin / ljk_admin**。
|
||||
|
||||
用法:平台工作台 → 某公司「管理该公司」→ 左侧出现角色/成员等 → 修改时两次确认。「返回平台工作台」回到公司列表。
|
||||
|
||||
开发演示数据:「演示公司」+ 账号 demo/demo123,与超管 ljk_admin 是不同身份。
|
||||
|
||||
常用权限:读取/写入/发布模块;数据 CRUD 与导入导出;上传下载;审计;管理智能体;邀请成员;管理组织;数据同步。写入模块=保存在建草稿;发布模块=上线。
|
||||
|
||||
新建公司默认全量公司权限(可收窄至空)。创建时同步生成该公司**管理员**账号(**用户名随机全局唯一**、初始密码随机;明文仅创建时展示一次;登录后可自行「修改密码」)。成员管理也可直接「新建成员」(同样随机用户名)。
|
||||
|
||||
每家公司有全局唯一 **路径 slug**(如 `demo` → 约定对外 `/{slug}/...`)。平台工作台创建/改名时可填;演示公司固定为 `demo`。规则:2–32 位、小写字母开头、仅 `a-z0-9-`;不可用 `api`/`admin`/`console` 等保留字。网关按 slug 分流属后续阶段。
|
||||
|
||||
## 一、公司成员角色
|
||||
|
||||
给真人登录账号用,存在用户表 / JWT 的 `role` 字段。
|
||||
|
||||
| 角色 | 能做什么 | 不能做什么 |
|
||||
|------|----------|------------|
|
||||
| **管理员** | 公司顶级权限:发布模块、管智能体/角色/组织/邀请、**数据同步**、全量数据 CRUD | — |
|
||||
| **编辑** | 读写业务数据、导入导出、保存草稿(写入模块) | 发布、管组织/邀请/同步、删行 |
|
||||
| **只读** | 看模块与数据、导出、下文件、看审计 | 任何写入、发布、管理类操作 |
|
||||
| **待加入** | 仅能注册后等待;需邀请码加入公司 | 一切业务能力 |
|
||||
| **智能体** | 不按上表套权限,而按所绑智能体角色的权限列表 | 不能配置「数据同步」(无该权限) |
|
||||
|
||||
邀请成员时可选项一般为:**编辑** / **只读** / **管理员**。
|
||||
|
||||
## 二、智能体角色(默认)
|
||||
|
||||
给 AI / 宿主程序用的服务账号,在「角色管理」里配置,编码与名称均为中文。
|
||||
|
||||
| 角色 | 适合场景 | 主要权限 |
|
||||
|------|----------|----------|
|
||||
| **生成发布** | 建站智能体最低可用集:生成蓝图并发布、导入样例数据 | 读取/发布模块、查询/导入数据、上传下载 |
|
||||
| **只读** | 只查询、导出的助手 | 读取模块、查询/导出数据、下载、审计 |
|
||||
| **读写** | 日常维护业务数据,不发布新模块 | 读写模块配置、增改查导入导出、文件 |
|
||||
| **运维** | 需要删数据、全量行操作与发布的运维机器人 | 含发布、删除及上列大部分能力 |
|
||||
|
||||
可在「角色管理」自定义角色并勾选中文权限;**不要**把「数据同步」赋给智能体(该权限仅管理员角色自带)。
|
||||
|
||||
## 三、与旧英文码
|
||||
|
||||
| 旧码 | 现中文 |
|
||||
|------|--------|
|
||||
| platform_admin / super_admin | 超级管理员 |
|
||||
| owner | 管理员 |
|
||||
| editor(成员) | 编辑 |
|
||||
| viewer(成员) | 只读 |
|
||||
| pending | 待加入 |
|
||||
| agent | 智能体 |
|
||||
| publisher | 生成发布 |
|
||||
| editor(智能体角色) | 读写 |
|
||||
| viewer(智能体角色) | 只读 |
|
||||
| operator | 运维 |
|
||||
|
||||
读写库与鉴权时会自动把旧英文码归一成中文;启动时默认智能体角色编码会尽量升级为中文。
|
||||
Reference in New Issue
Block a user