666 lines
15 KiB
Markdown
666 lines
15 KiB
Markdown
|
|
# V1 技术方案:绑定媒体账号与手动发送文章
|
|||
|
|
|
|||
|
|
> 口径说明:本文的插件执行流程、接口路径与会话模型已同步到主架构文档 [geo-platform-ops-admin-tech-architecture-v1.md](D:/project/geo/docs/geo-platform-ops-admin-tech-architecture-v1.md) 的 `§13.8 浏览器插件执行面闭环`、`§13.6.3 插件回调与内部接口`、`§13.6.4 统一错误响应与错误码`。若两份文档存在任何冲突,以主架构文档为准。
|
|||
|
|
|
|||
|
|
## 1. 文档目标
|
|||
|
|
|
|||
|
|
本文档用于落地一套与文擎 GEO 当前形态接近的系统能力,聚焦两个核心功能:
|
|||
|
|
|
|||
|
|
- 绑定媒体账号
|
|||
|
|
- 手动发送文章到媒体平台
|
|||
|
|
|
|||
|
|
当前版本边界:
|
|||
|
|
|
|||
|
|
- 支持平台账号绑定
|
|||
|
|
- 支持后台文章列表中手动点击发送
|
|||
|
|
- 支持插件执行真实发文
|
|||
|
|
- 不支持自动定时发送到媒体平台
|
|||
|
|
- 可支持后台定时生成文章,但生成与发送解耦
|
|||
|
|
|
|||
|
|
## 2. 产品边界
|
|||
|
|
|
|||
|
|
### 2.1 当前 V1 包含
|
|||
|
|
|
|||
|
|
- Web 管理后台
|
|||
|
|
- 媒体账号绑定页
|
|||
|
|
- 文章列表与文章详情页
|
|||
|
|
- 发送按钮与发送结果展示
|
|||
|
|
- 浏览器插件作为本地执行器
|
|||
|
|
- 平台适配层
|
|||
|
|
- 发送记录与状态记录
|
|||
|
|
|
|||
|
|
### 2.2 当前 V1 不包含
|
|||
|
|
|
|||
|
|
- 自动定时发送
|
|||
|
|
- 云端代发
|
|||
|
|
- 平台 cookie 或登录票据上传到服务端
|
|||
|
|
- 复杂运营数据回流
|
|||
|
|
- 多终端执行器调度
|
|||
|
|
|
|||
|
|
## 3. 总体架构
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
flowchart LR
|
|||
|
|
A["Web 前端"] --> B["业务后端 API"]
|
|||
|
|
A <---> C["浏览器插件"]
|
|||
|
|
C --> D["平台适配层"]
|
|||
|
|
D --> E["头条 / 百家 / 知乎 / 网易等平台"]
|
|||
|
|
B --> F["PostgreSQL"]
|
|||
|
|
B --> G["对象存储"]
|
|||
|
|
C --> H["/api/callback/plugin/*"]
|
|||
|
|
H --> B
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 4. 角色与职责
|
|||
|
|
|
|||
|
|
### 4.1 Web 前端
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 展示媒体账号绑定状态
|
|||
|
|
- 展示文章列表和发送入口
|
|||
|
|
- 调用后端读取文章详情、创建 `plugin_session`、展示即时执行结果
|
|||
|
|
- 调用插件执行绑定与发文动作
|
|||
|
|
|
|||
|
|
前端不负责:
|
|||
|
|
|
|||
|
|
- 直接登录媒体平台
|
|||
|
|
- 直接调用媒体平台发布接口
|
|||
|
|
|
|||
|
|
### 4.2 业务后端
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 租户、文章、平台账号绑定关系管理
|
|||
|
|
- `plugin_session` 创建、校验与过期控制
|
|||
|
|
- 发送记录管理
|
|||
|
|
- 文章详情与资源存储
|
|||
|
|
- 结果审计与失败追踪
|
|||
|
|
|
|||
|
|
后端不负责:
|
|||
|
|
|
|||
|
|
- 代替用户持有平台登录态
|
|||
|
|
- 直接模拟媒体平台发文
|
|||
|
|
|
|||
|
|
### 4.3 浏览器插件
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 打开平台官网登录页
|
|||
|
|
- 检测平台登录状态
|
|||
|
|
- 获取当前绑定账号信息
|
|||
|
|
- 上传图片
|
|||
|
|
- 调用平台接口或执行页面内发布逻辑
|
|||
|
|
- 将真实执行结果双通道返回:即时回传 Web + 回调后端可靠落库
|
|||
|
|
|
|||
|
|
### 4.4 平台适配层
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
- 每个平台单独封装接入逻辑
|
|||
|
|
- 对上暴露统一接口
|
|||
|
|
- 对下适配各平台差异
|
|||
|
|
|
|||
|
|
## 5. 核心设计原则
|
|||
|
|
|
|||
|
|
- 生成与发送分离
|
|||
|
|
- 控制面与执行面分离
|
|||
|
|
- 网站负责业务状态,插件负责真实执行
|
|||
|
|
- 服务端不存储平台 cookie
|
|||
|
|
- 每个平台使用独立 adapter
|
|||
|
|
|
|||
|
|
## 6. 绑定媒体账号方案
|
|||
|
|
|
|||
|
|
### 6.1 业务目标
|
|||
|
|
|
|||
|
|
用户在后台点击“去绑定”后,前端先创建一次性 `plugin_session`。插件打开对应平台官网登录页。用户完成登录后,插件识别账号信息并即时回传前端,同时调用回调 API 持久化绑定关系。
|
|||
|
|
|
|||
|
|
### 6.2 绑定流程
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant U as 用户
|
|||
|
|
participant W as Web前端
|
|||
|
|
participant P as 插件
|
|||
|
|
participant M as 媒体平台
|
|||
|
|
participant B as 后端
|
|||
|
|
|
|||
|
|
U->>W: 点击去绑定
|
|||
|
|
W->>B: 创建 plugin_session(bind)
|
|||
|
|
B-->>W: pluginSessionId + sessionToken
|
|||
|
|
W->>P: openBindPage(platformId, loginUrl, ctx)
|
|||
|
|
P->>M: 打开登录页
|
|||
|
|
loop 轮询检测
|
|||
|
|
P->>M: checkLogin / getUserInfo
|
|||
|
|
M-->>P: 未登录或已登录账号信息
|
|||
|
|
end
|
|||
|
|
P-->>W: bindingDetected(platformId, platformUid, nickname, avatar)
|
|||
|
|
P->>B: POST /api/callback/plugin/bind
|
|||
|
|
B-->>P: 持久化成功
|
|||
|
|
B-->>W: SSE / 轮询可见最新状态
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.3 绑定执行细节
|
|||
|
|
|
|||
|
|
1. 前端先向后端申请 `plugin_session`
|
|||
|
|
2. 后端返回 `pluginSessionId + sessionToken + expireAt`
|
|||
|
|
3. 前端发起插件调用 `openBindPage`
|
|||
|
|
4. 插件创建平台官网登录标签页
|
|||
|
|
5. 插件定时轮询平台账号状态
|
|||
|
|
6. 插件检测到 `platformUid` 后,先向网页回传绑定事件用于即时反馈
|
|||
|
|
7. 插件再调用 `/api/callback/plugin/bind` 可靠落库
|
|||
|
|
8. 后端写入 `platform_accounts` 并更新页面状态
|
|||
|
|
|
|||
|
|
### 6.4 绑定状态定义
|
|||
|
|
|
|||
|
|
- `active`:绑定有效
|
|||
|
|
- `invalid`:账号失效或检测失败
|
|||
|
|
- `expired`:账号登录态过期
|
|||
|
|
- `pending`:等待绑定结果
|
|||
|
|
|
|||
|
|
## 7. 手动发送文章方案
|
|||
|
|
|
|||
|
|
### 7.1 业务目标
|
|||
|
|
|
|||
|
|
用户在文章列表页点击发送按钮后,前端先创建一次性 `plugin_session`,再由插件读取文章内容并执行真实发文。发布结果即时回传页面,同时通过回调接口可靠写入后台。
|
|||
|
|
|
|||
|
|
### 7.2 发送流程
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
sequenceDiagram
|
|||
|
|
participant U as 用户
|
|||
|
|
participant W as Web前端
|
|||
|
|
participant B as 后端
|
|||
|
|
participant P as 插件
|
|||
|
|
participant M as 媒体平台
|
|||
|
|
|
|||
|
|
U->>W: 点击发送按钮
|
|||
|
|
W->>B: 创建 plugin_session(publish)
|
|||
|
|
B-->>W: pluginSessionId + sessionToken
|
|||
|
|
W->>B: 获取文章详情
|
|||
|
|
B-->>W: 返回标题/正文/封面/图片
|
|||
|
|
W->>P: publishArticle(payload, ctx)
|
|||
|
|
P->>P: 检查绑定账号与登录状态
|
|||
|
|
P->>M: 上传图片
|
|||
|
|
P->>M: 发布文章
|
|||
|
|
M-->>P: 返回 articleId / status
|
|||
|
|
P-->>W: 发布结果
|
|||
|
|
P->>B: POST /api/callback/plugin/publish
|
|||
|
|
B-->>P: 持久化成功
|
|||
|
|
B-->>W: SSE / 轮询更新页面状态
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7.3 发送执行细节
|
|||
|
|
|
|||
|
|
1. 前端先读取插件状态与最低兼容版本,不满足时直接阻断按钮
|
|||
|
|
2. 前端从后端创建 `plugin_session`
|
|||
|
|
3. 前端从后端读取文章详情
|
|||
|
|
4. 前端构造发送请求并调用插件
|
|||
|
|
5. 插件检查对应平台账号是否已绑定且仍有效
|
|||
|
|
6. 插件上传封面与正文图片
|
|||
|
|
7. 插件按平台 adapter 执行发布
|
|||
|
|
8. 插件先向页面返回结果,再回调 `/api/callback/plugin/publish`
|
|||
|
|
9. 页面通过 SSE 或轮询刷新显示最新状态
|
|||
|
|
|
|||
|
|
### 7.4 发送状态定义
|
|||
|
|
|
|||
|
|
- `running`:发送中
|
|||
|
|
- `success`:发送成功
|
|||
|
|
- `failed`:发送失败
|
|||
|
|
- `draft`:保存草稿成功
|
|||
|
|
- `pending_review`:平台审核中
|
|||
|
|
|
|||
|
|
## 8. 前后端接口设计
|
|||
|
|
|
|||
|
|
本节接口默认遵循主架构文档中的统一错误响应规范,失败时返回统一的 `code / message / detail / request_id` 结构。
|
|||
|
|
|
|||
|
|
### 8.1 绑定相关接口
|
|||
|
|
|
|||
|
|
#### `POST /api/tenant/media/plugin-sessions`
|
|||
|
|
|
|||
|
|
请求体:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"actionType": "bind",
|
|||
|
|
"platformId": "zhihu"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
响应:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"pluginSessionId": "ps_xxx",
|
|||
|
|
"sessionToken": "st_xxx",
|
|||
|
|
"expireAt": "2026-03-26T12:00:00+08:00",
|
|||
|
|
"minPluginVersion": "1.0.0"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `GET /api/tenant/media/platform-accounts`
|
|||
|
|
|
|||
|
|
返回当前用户的媒体账号列表。
|
|||
|
|
|
|||
|
|
#### `POST /api/tenant/media/platform-accounts/{id}/check`
|
|||
|
|
|
|||
|
|
触发一次重新检测,用于刷新登录有效性。前端应先创建 `plugin_session(actionType=check)`,再调用插件执行检查。
|
|||
|
|
|
|||
|
|
### 8.2 文章与发送接口
|
|||
|
|
|
|||
|
|
#### `GET /api/tenant/articles/{id}`
|
|||
|
|
|
|||
|
|
返回文章详情:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"id": "art_xxx",
|
|||
|
|
"title": "文章标题",
|
|||
|
|
"htmlContent": "<p>...</p>",
|
|||
|
|
"markdownContent": "## ...",
|
|||
|
|
"coverUrl": "https://xxx/cover.png",
|
|||
|
|
"imageList": ["https://xxx/1.png"]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `GET /api/tenant/media/publish-records?articleId=art_xxx`
|
|||
|
|
|
|||
|
|
查询指定文章的所有发送记录。
|
|||
|
|
|
|||
|
|
### 8.3 插件回调接口
|
|||
|
|
|
|||
|
|
#### `POST /api/callback/plugin/bind`
|
|||
|
|
|
|||
|
|
请求体:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"pluginSessionId": "ps_xxx",
|
|||
|
|
"sessionToken": "st_xxx",
|
|||
|
|
"platformId": "zhihu",
|
|||
|
|
"platformUid": "708996890603040768",
|
|||
|
|
"nickname": "CharmingGeeker",
|
|||
|
|
"avatarUrl": "https://xxx/avatar.png",
|
|||
|
|
"clientVersion": "1.0.0",
|
|||
|
|
"metadata": {}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `POST /api/callback/plugin/publish`
|
|||
|
|
|
|||
|
|
请求体:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"pluginSessionId": "ps_xxx",
|
|||
|
|
"sessionToken": "st_xxx",
|
|||
|
|
"articleId": "art_xxx",
|
|||
|
|
"platformAccountId": "pa_xxx",
|
|||
|
|
"platformId": "zhihu",
|
|||
|
|
"status": "success",
|
|||
|
|
"clientVersion": "1.0.0",
|
|||
|
|
"requestPayload": {},
|
|||
|
|
"responsePayload": {},
|
|||
|
|
"externalArticleId": "1234567890",
|
|||
|
|
"errorMessage": null
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### `POST /api/callback/plugin/check`
|
|||
|
|
|
|||
|
|
用于账号重检结果回写,负载与绑定接口类似,但语义是刷新已有 `platform_account` 状态。
|
|||
|
|
|
|||
|
|
## 9. 插件消息协议
|
|||
|
|
|
|||
|
|
### 9.1 插件可用性检测
|
|||
|
|
|
|||
|
|
页面加载时先执行:
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
type PluginPingResp = {
|
|||
|
|
installed: boolean;
|
|||
|
|
version?: string;
|
|||
|
|
capabilities?: Array<"bind" | "publish" | "checkStatus">;
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
若未安装、被禁用或版本低于后端下发的 `minPluginVersion`,页面必须禁用绑定与发送按钮。
|
|||
|
|
|
|||
|
|
### 9.2 绑定媒体
|
|||
|
|
|
|||
|
|
共享上下文:
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
type ExecContext = {
|
|||
|
|
pluginSessionId: string;
|
|||
|
|
sessionToken: string;
|
|||
|
|
minPluginVersion: string;
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
请求:
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
type OpenBindPageReq = {
|
|||
|
|
platformId: string;
|
|||
|
|
loginUrl: string;
|
|||
|
|
ctx: ExecContext;
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
回调事件:
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
type BindingDetectedEvent = {
|
|||
|
|
pluginSessionId: string;
|
|||
|
|
platformId: string;
|
|||
|
|
platformUid: string;
|
|||
|
|
nickname: string;
|
|||
|
|
avatarUrl?: string;
|
|||
|
|
metadata?: Record<string, unknown>;
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 9.3 发送文章
|
|||
|
|
|
|||
|
|
请求:
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
type PublishArticleReq = {
|
|||
|
|
articleId: string;
|
|||
|
|
platformId: string;
|
|||
|
|
platformAccountId: string;
|
|||
|
|
title: string;
|
|||
|
|
htmlContent: string;
|
|||
|
|
markdownContent?: string;
|
|||
|
|
coverUrl?: string;
|
|||
|
|
imageList?: string[];
|
|||
|
|
publishType: "publish" | "draft";
|
|||
|
|
ctx: ExecContext;
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
响应:
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
type PublishArticleResp = {
|
|||
|
|
success: boolean;
|
|||
|
|
pluginSessionId: string;
|
|||
|
|
platformId: string;
|
|||
|
|
externalArticleId?: string;
|
|||
|
|
status?: "draft" | "pending_review" | "published" | "failed";
|
|||
|
|
message?: string;
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 10. 数据模型
|
|||
|
|
|
|||
|
|
### 10.1 平台账号表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
create table platform_accounts (
|
|||
|
|
id varchar(64) primary key,
|
|||
|
|
tenant_id varchar(64) not null,
|
|||
|
|
user_id varchar(64) not null,
|
|||
|
|
platform_id varchar(64) not null,
|
|||
|
|
platform_uid varchar(128) not null,
|
|||
|
|
nickname varchar(255) not null,
|
|||
|
|
avatar_url text null,
|
|||
|
|
status varchar(32) not null,
|
|||
|
|
metadata_json jsonb null,
|
|||
|
|
last_check_at timestamp null,
|
|||
|
|
created_at timestamp not null,
|
|||
|
|
updated_at timestamp not null
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
唯一约束建议:
|
|||
|
|
|
|||
|
|
- `(tenant_id, user_id, platform_id, platform_uid)`
|
|||
|
|
|
|||
|
|
### 10.2 插件会话表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
create table plugin_sessions (
|
|||
|
|
id varchar(64) primary key,
|
|||
|
|
tenant_id varchar(64) not null,
|
|||
|
|
user_id varchar(64) not null,
|
|||
|
|
action_type varchar(32) not null,
|
|||
|
|
platform_id varchar(64) not null,
|
|||
|
|
session_token varchar(128) not null,
|
|||
|
|
client_version varchar(32) null,
|
|||
|
|
expire_at timestamp not null,
|
|||
|
|
status varchar(32) not null,
|
|||
|
|
created_at timestamp not null,
|
|||
|
|
updated_at timestamp not null
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 10.3 文章表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
create table articles (
|
|||
|
|
id varchar(64) primary key,
|
|||
|
|
tenant_id varchar(64) not null,
|
|||
|
|
user_id varchar(64) not null,
|
|||
|
|
title varchar(500) not null,
|
|||
|
|
html_content text not null,
|
|||
|
|
markdown_content text null,
|
|||
|
|
cover_url text null,
|
|||
|
|
image_list_json jsonb null,
|
|||
|
|
status varchar(32) not null,
|
|||
|
|
created_at timestamp not null,
|
|||
|
|
updated_at timestamp not null
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 10.4 发送记录表
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
create table publish_records (
|
|||
|
|
id varchar(64) primary key,
|
|||
|
|
tenant_id varchar(64) not null,
|
|||
|
|
article_id varchar(64) not null,
|
|||
|
|
platform_account_id varchar(64) not null,
|
|||
|
|
platform_id varchar(64) not null,
|
|||
|
|
status varchar(32) not null,
|
|||
|
|
request_payload_json jsonb null,
|
|||
|
|
response_payload_json jsonb null,
|
|||
|
|
external_article_id varchar(128) null,
|
|||
|
|
error_message text null,
|
|||
|
|
created_at timestamp not null,
|
|||
|
|
updated_at timestamp not null
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11. 平台适配层设计
|
|||
|
|
|
|||
|
|
每个平台实现统一接口:
|
|||
|
|
|
|||
|
|
```ts
|
|||
|
|
interface PlatformAdapter {
|
|||
|
|
platformId: string;
|
|||
|
|
|
|||
|
|
checkLogin(ctx: ExecContext): Promise<LoginInfo | null>;
|
|||
|
|
openBindPage(ctx: ExecContext): Promise<void>;
|
|||
|
|
uploadImage(input: UploadInput, ctx: ExecContext): Promise<{ url: string }>;
|
|||
|
|
publish(input: PublishInput, ctx: ExecContext): Promise<PublishArticleResp>;
|
|||
|
|
checkStatus(input: CheckStatusInput, ctx: ExecContext): Promise<{ status: string }>;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
V1 推荐先做 1 个平台打通全链路,再扩展其他平台。
|
|||
|
|
|
|||
|
|
推荐顺序:
|
|||
|
|
|
|||
|
|
1. 知乎
|
|||
|
|
2. 头条号
|
|||
|
|
3. 百家号
|
|||
|
|
4. 网易号
|
|||
|
|
|
|||
|
|
## 12. 插件实现要求
|
|||
|
|
|
|||
|
|
### 12.1 注入与通信
|
|||
|
|
|
|||
|
|
- 只注入本系统后台域名
|
|||
|
|
- 通过受控 `postMessage` 或 `runtime.sendMessage` 通信
|
|||
|
|
- 所有消息必须校验来源域名和会话信息
|
|||
|
|
- 必须支持 `plugin.ping`,返回安装状态、版本号和能力清单
|
|||
|
|
- 所有绑定 / 检测 / 发布动作都必须带上 `pluginSessionId + sessionToken`
|
|||
|
|
|
|||
|
|
### 12.2 执行逻辑
|
|||
|
|
|
|||
|
|
- 打开登录页
|
|||
|
|
- 轮询登录状态
|
|||
|
|
- 上传图片
|
|||
|
|
- 发布文章
|
|||
|
|
- 返回结果
|
|||
|
|
- 绑定和发布结果必须“先即时回传页面,再回调后端可靠落库”
|
|||
|
|
- 回调接口必须按 `plugin_session_id + callback_stage` 做幂等
|
|||
|
|
|
|||
|
|
### 12.3 V1 不要求
|
|||
|
|
|
|||
|
|
- 后台常驻拉任务
|
|||
|
|
- 自动定时发送
|
|||
|
|
- 云端远程控制
|
|||
|
|
|
|||
|
|
## 13. 安全要求
|
|||
|
|
|
|||
|
|
- 服务端不保存平台 cookie
|
|||
|
|
- 插件与页面通信必须校验 `origin`
|
|||
|
|
- 所有绑定与发送操作写审计日志
|
|||
|
|
- 后端保存文章与发送结果,便于追查
|
|||
|
|
- 平台 UID、昵称、头像可持久化,敏感票据只存在本地执行环境
|
|||
|
|
- 回调接口只信任 `session_token`,不信任浏览器 Cookie
|
|||
|
|
- 插件只允许向受信后台域名发消息与回调
|
|||
|
|
|
|||
|
|
## 14. 错误处理
|
|||
|
|
|
|||
|
|
### 14.1 绑定失败
|
|||
|
|
|
|||
|
|
常见原因:
|
|||
|
|
|
|||
|
|
- 用户未完成平台登录
|
|||
|
|
- 平台页面结构变化
|
|||
|
|
- 平台接口返回异常
|
|||
|
|
- 插件未安装或版本过低
|
|||
|
|
|
|||
|
|
处理方式:
|
|||
|
|
|
|||
|
|
- 前端提示失败原因
|
|||
|
|
- 保持账号状态为 `pending` 或 `invalid`
|
|||
|
|
- 支持重新检测
|
|||
|
|
- 提供插件安装或升级引导
|
|||
|
|
|
|||
|
|
### 14.2 发送失败
|
|||
|
|
|
|||
|
|
常见原因:
|
|||
|
|
|
|||
|
|
- 平台账号失效
|
|||
|
|
- 图片上传失败
|
|||
|
|
- 平台接口改版
|
|||
|
|
- 平台风控或审核限制
|
|||
|
|
- 插件回调超时
|
|||
|
|
|
|||
|
|
处理方式:
|
|||
|
|
|
|||
|
|
- 记录失败原因
|
|||
|
|
- 返回具体 message
|
|||
|
|
- 发送记录保留原始结果
|
|||
|
|
- 回调失败进入补偿队列
|
|||
|
|
|
|||
|
|
## 15. 页面最小落地范围
|
|||
|
|
|
|||
|
|
### 15.1 媒体账号页
|
|||
|
|
|
|||
|
|
- 平台列表
|
|||
|
|
- 绑定状态
|
|||
|
|
- 去绑定按钮
|
|||
|
|
- 重新检测按钮
|
|||
|
|
- 插件安装 / 版本状态提示
|
|||
|
|
|
|||
|
|
### 15.2 文章列表页
|
|||
|
|
|
|||
|
|
- 文章标题
|
|||
|
|
- 文章状态
|
|||
|
|
- 发送按钮
|
|||
|
|
- 查看详情
|
|||
|
|
- 查看发送记录
|
|||
|
|
|
|||
|
|
### 15.3 发送记录页
|
|||
|
|
|
|||
|
|
- 平台
|
|||
|
|
- 发送时间
|
|||
|
|
- 发送状态
|
|||
|
|
- 平台文章 ID
|
|||
|
|
- 错误原因
|
|||
|
|
|
|||
|
|
## 16. 开发顺序
|
|||
|
|
|
|||
|
|
### 阶段 1:业务后端
|
|||
|
|
|
|||
|
|
- 建表
|
|||
|
|
- `plugin_session` 接口
|
|||
|
|
- 文章接口
|
|||
|
|
- 插件回调接口
|
|||
|
|
- 发送记录查询接口
|
|||
|
|
|
|||
|
|
### 阶段 2:Web 前端
|
|||
|
|
|
|||
|
|
- 媒体管理页
|
|||
|
|
- 文章列表与发送按钮
|
|||
|
|
- 发送记录页
|
|||
|
|
- 插件可用性检测与降级提示
|
|||
|
|
|
|||
|
|
### 阶段 3:插件基础层
|
|||
|
|
|
|||
|
|
- 页面通信
|
|||
|
|
- `plugin.ping`
|
|||
|
|
- 打开登录页
|
|||
|
|
- 回传绑定结果
|
|||
|
|
- 回调后端接口
|
|||
|
|
|
|||
|
|
### 阶段 4:首个平台 adapter
|
|||
|
|
|
|||
|
|
- 先打通绑定
|
|||
|
|
- 再打通发文
|
|||
|
|
- 最后接状态查询
|
|||
|
|
|
|||
|
|
### 阶段 5:扩展更多平台
|
|||
|
|
|
|||
|
|
- 复制 adapter 结构
|
|||
|
|
- 按平台差异逐个接入
|
|||
|
|
|
|||
|
|
## 17. V1 验收标准
|
|||
|
|
|
|||
|
|
### 17.1 绑定媒体
|
|||
|
|
|
|||
|
|
- 可成功绑定至少 1 个平台
|
|||
|
|
- 可显示账号昵称和头像
|
|||
|
|
- 可执行重新检测
|
|||
|
|
- 插件能通过回调接口落库绑定关系
|
|||
|
|
|
|||
|
|
### 17.2 手动发送
|
|||
|
|
|
|||
|
|
- 从后台文章列表点击发送
|
|||
|
|
- 插件接收文章内容并发文
|
|||
|
|
- 平台返回文章 ID
|
|||
|
|
- 插件能通过回调接口保存发送记录
|
|||
|
|
- 前端可看到发送成功或失败状态
|
|||
|
|
|
|||
|
|
## 18. 后续演进方向
|
|||
|
|
|
|||
|
|
V2 可扩展:
|
|||
|
|
|
|||
|
|
- 多平台批量发送
|
|||
|
|
- 发送前 AI 优化
|
|||
|
|
- 发送后状态轮询
|
|||
|
|
- 草稿箱管理
|
|||
|
|
|
|||
|
|
V3 可扩展:
|
|||
|
|
|
|||
|
|
- 本地 agent 常驻
|
|||
|
|
- 自动定时发送
|
|||
|
|
- 多执行器调度
|
|||
|
|
- 失败重试与补偿
|