feat(page-data): complete Phase 4-5, ops UI, and publish integration
Add visitor roles, row-level scope, owner ops APIs, MySQL policy index, Turnstile captcha, browser client SDK, publish-panel dataset binding, acceptance tests, and usage documentation. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
日期: 2026-07-08
|
||||
|
||||
状态: Draft,仅开发设计;本文不代表已实现。
|
||||
状态: 已实现(Phase 1–5 + 产品层);以代码与 `docs/page-data-api-usage.md` 为准。
|
||||
|
||||
## 1. 背景
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
# Page Data API 使用说明
|
||||
|
||||
面向 MindSpace 页面 owner、Agent 与 HTML 页面开发者。实现细节见 [page-data-api-public-access-plan-20260708.md](architecture/page-data-api-public-access-plan-20260708.md)。
|
||||
|
||||
## 快速路径
|
||||
|
||||
1. **Agent** 用 `private_data_execute` 建表,用 `private_data_register_dataset` 注册 dataset。
|
||||
2. **发布页面** 时在发布面板勾选「启用页面数据」,选择 dataset 与公开能力;或发布后让 Agent 调用 `private_data_set_page_policy`。
|
||||
3. **HTML 页面** 引入 `/assets/page-data-client.js`,用 `MindSpacePageData.createClient({ pageId })` 读写数据。
|
||||
4. **运维** 在 MindSpace 页面详情「页面数据」面板查看日志、导出、撤销令牌、恢复软删除、关闭 dataset。
|
||||
|
||||
## 访问模式与默认能力
|
||||
|
||||
| 发布访问模式 | Page Data 模式 | 默认公开能力 |
|
||||
|-------------|----------------|-------------|
|
||||
| 完全公开 | `public` | 仅 insert |
|
||||
| 口令访问 | `password` | read + insert |
|
||||
| 登录访问 | `login_required` | read + insert + update |
|
||||
|
||||
可在发布面板或策略中逐项覆盖。
|
||||
|
||||
## Owner API(需登录)
|
||||
|
||||
```text
|
||||
GET /api/page-data # 列出已注册 dataset
|
||||
GET /api/page-data/:dataset # 读行
|
||||
POST /api/page-data/:dataset/rows # 插入
|
||||
GET /api/page-data/:dataset/schema
|
||||
GET /api/page-data/:dataset/stats
|
||||
GET /api/page-data/:dataset/export?format=json|csv
|
||||
POST /api/page-data/:dataset/rows/:id/restore
|
||||
|
||||
GET /api/page-data/policies
|
||||
GET /api/page-data/policies/:pageId
|
||||
PUT /api/page-data/policies/:pageId
|
||||
POST /api/page-data/policies/:pageId/apply-publish
|
||||
GET /api/page-data/policies/:pageId/ops
|
||||
GET /api/page-data/policies/:pageId/logs
|
||||
POST /api/page-data/policies/:pageId/tokens/revoke
|
||||
POST /api/page-data/policies/:pageId/password/reset
|
||||
POST /api/page-data/policies/:pageId/datasets/:dataset/close
|
||||
```
|
||||
|
||||
## 公开 API(无需平台登录)
|
||||
|
||||
```text
|
||||
POST /api/public/pages/:pageId/data-auth # 口令页换 token
|
||||
GET /api/public/pages/:pageId/data/:dataset
|
||||
POST /api/public/pages/:pageId/data/:dataset/rows
|
||||
PATCH /api/public/pages/:pageId/data/:dataset/rows/:id
|
||||
DELETE /api/public/pages/:pageId/data/:dataset/rows/:id
|
||||
GET /api/public/pages/:pageId/data/:dataset/schema
|
||||
GET /api/public/pages/:pageId/data/:dataset/stats
|
||||
```
|
||||
|
||||
公开请求可带 `x-page-data-token`(口令/登录会话)。**公开页不能直接传 SQL**,只能提交策略白名单字段。
|
||||
|
||||
## HTML 页面嵌入
|
||||
|
||||
```html
|
||||
<script src="/assets/page-data-client.js"></script>
|
||||
<script>
|
||||
const client = MindSpacePageData.createClient({
|
||||
pageId: '你的页面 UUID',
|
||||
apiBase: '/api',
|
||||
});
|
||||
|
||||
// 口令页先认证
|
||||
// await client.authenticate('页面口令');
|
||||
|
||||
// 列表
|
||||
const { rows } = await client.listRows('signups', { limit: 20 });
|
||||
|
||||
// 提交表单
|
||||
await client.insertRow('signups', { name: '张三', phone: '13800000000' });
|
||||
</script>
|
||||
```
|
||||
|
||||
### 公开表单 + Cloudflare Turnstile
|
||||
|
||||
服务端配置环境变量 `PAGE_DATA_TURNSTILE_SECRET` 后,**完全公开**模式的 insert 必须带验证码。
|
||||
|
||||
```html
|
||||
<script src="/assets/page-data-client.js"></script>
|
||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
||||
<div class="cf-turnstile" data-sitekey="你的站点密钥"></div>
|
||||
<form id="signup">
|
||||
<input name="name" required />
|
||||
<button type="submit">提交</button>
|
||||
</form>
|
||||
<script>
|
||||
const client = MindSpacePageData.createClient({ pageId: '页面UUID' });
|
||||
document.getElementById('signup').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const name = e.target.name.value.trim();
|
||||
const token = turnstile.getResponse();
|
||||
await client.insertRow('signups', { name }, { turnstileToken: token });
|
||||
turnstile.reset();
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
验证码 token 也可放在请求体 `turnstile_token` / `captcha_token`,或通过头 `x-page-data-captcha` 传递。
|
||||
|
||||
## Agent MCP 工具
|
||||
|
||||
- `private_data_register_dataset` — 注册 dataset
|
||||
- `private_data_set_page_policy` — 为已发布页写 Page Access Policy
|
||||
- `private_data_close_page_dataset` — 关闭某 dataset 的公开访问
|
||||
|
||||
## 本地验证
|
||||
|
||||
```bash
|
||||
node --test page-data-acceptance.test.mjs page-data-integration.test.mjs page-data-public-service.test.mjs
|
||||
node scripts/run-memind-tests.mjs --mode changed
|
||||
```
|
||||
|
||||
## 安全提醒
|
||||
|
||||
- 公开读默认关闭;开启前确认字段不含敏感信息。
|
||||
- 密码访问无法强身份绑定,仅适合轻量协作。
|
||||
- 生产公开写入建议开启 Turnstile 并监控「页面数据」操作日志。
|
||||
Reference in New Issue
Block a user