# EveryPublish 服务端接口文档(v1) > 基地址:`/api/v1` · 统一响应:`{"code":0,"message":"ok","data":{...}}`,code!=0 为业务错误。 > 认证:`Authorization: Bearer `(15min,前端自动用 refresh 轮换)。 ## 业务错误码 | code | 含义 | |---|---| | 1001 | 参数不合法 | | 1002 | 未登录/令牌无效 | | 1003 | 无权限 | | 1004 | 资源不存在 | | 2001 | 邮箱已注册 | | 2002 | 邮箱或密码错误 | | 2003 | 刷新令牌无效 | | 2004 | 已是成员 | | 2005 | 邀请链接无效或过期 | | 1006 | 需要两步验证(2FA,默认关) | | 3001-3005 | 业务冲突(账号不可删/已绑定/挑战已结束/链接过期/任务状态不允许) | ## 认证 /auth | 方法 | 路径 | 说明 | |---|---|---| | POST | /auth/register | 注册 {email,password,nickname} → 返回令牌对+用户+默认工作空间 | | POST | /auth/login | 登录 {email,password} → 令牌对+用户 | | POST | /auth/refresh | {refreshToken} → 轮换新令牌对(旧 refresh 立即吊销) | | POST | /auth/logout | 登出(吊销 refresh) | | GET | /auth/me | 当前用户+工作空间+角色 | ## 工作空间 /workspaces(登录) | 方法 | 路径 | 说明 | |---|---|---| | POST | /workspaces | 创建 {name}(创建者为 owner) | | GET | /workspaces | 我所在的工作空间列表 | | PUT | /workspaces/:id | 改名(owner/admin) | ## 成员 /members(登录) | 方法 | 路径 | 说明 | |---|---|---| | GET | /members | 成员列表(含 email/nickname) | | POST | /members/invite | 邀请 {email,role} → {token,link}(owner/admin;role: admin/operator/reviewer/viewer) | | POST | /members/join | 接受邀请 {token}(须与登录邮箱一致) | | PUT | /members/:id/role | 改角色 {role}(不可改 owner) | | DELETE | /members/:id | 移除(不可移除 owner) | ## 账号台账 /accounts(登录) | 方法 | 路径 | 说明 | |---|---|---| | GET | /accounts?platform=&status=&page=&size= | 台账列表(状态:unbound/binding/active/suspended/expired) | | POST | /accounts | 新增 {platform(douyin/kuaishou/xiaohongshu/bilibili),accountName,avatarUrl?,ipProfile?} | | PUT | /accounts/:id | 改资料(名称/头像/IP 画像) | | DELETE | /accounts/:id | 删除(仅 unbound) | | POST | /accounts/:id/bind | 发起绑定 → 创建挑战记录(status→binding)→ {challengeId} | ## 素材 /materials(登录) | 方法 | 路径 | 说明 | |---|---|---| | GET | /materials?kind=&group=&page=&size= | 素材列表 | | POST | /materials | multipart 上传:file 字段 + 可选 group/tags;流式 sha256,同工作区去重(dedup:true 返回已有素材) | | GET | /materials/:id/url | 生成签名直链(10 分钟、一次性)→ {url,expiresAt} | | DELETE | /materials/:id | 删除素材及文件 | | GET | /files/:token | 凭 token 下载文件(无鉴权,token 即凭证;一次性) | ## 任务 /tasks(登录;状态机) ```mermaid flowchart LR D[draft] -->|submit| P[pending_review] P -->|approve| Q[queued] -->|dispatch| DP[dispatched] -->|start| R[running] R -->|success| S[success] R -->|fail| F[failed] -->|retry| Q R -->|suspend| SU[suspended] -->|resume| Q P -->|reject| RJ[rejected] -->|resubmit| P D -->|cancel| C[cancelled] Q -->|cancel| C DP -->|cancel| C R -->|cancel| C SU -->|cancel| C ``` | 方法 | 路径 | 说明 | |---|---|---| | GET | /tasks?status=&schedule=&page=&size= | 任务列表 | | POST | /tasks | 新建草稿 {title,content?,tags?,accountIds[],materialIds[],scheduleAt?(unix ms),priority?(1-10)} | | GET | /tasks/:id | 详情 | | PUT | /tasks/:id | 编辑(仅 draft/rejected) | | DELETE | /tasks/:id | 删除(仅 draft) | | POST | /tasks/:id/submit | 提交审核 | | POST | /tasks/:id/approve | 审核通过 → queued(通知创建人) | | POST | /tasks/:id/reject | 驳回 {note}(通知创建人) | | POST | /tasks/:id/resubmit | 驳回后重提 | | POST | /tasks/:id/retry | 失败重试 → queued | | POST | /tasks/:id/cancel | 取消 | ## 挑战 /challenges(登录) | 方法 | 路径 | 说明 | |---|---|---| | GET | /challenges?status=&accountId= | 挑战列表(过期自动置 expired) | | POST | /challenges/:id/solve | 人工完成 {value?}(验证码/APP 确认;扫码由 Agent 完成) | | POST | /challenges/:id/resend | 一键重发(expired/suspended → active,重置 30min) | | POST | /challenges/:id/suspend | 挂起 | ## 通知 /notifications(登录) | 方法 | 路径 | 说明 | |---|---|---| | GET | /notifications?kind= | 我的通知 + unread 计数 | | POST | /notifications/:id/read | 标记已读 | | POST | /notifications/read-all | 全部已读 | ## 审计 /audit-logs(登录) | 方法 | 路径 | 说明 | |---|---|---| | GET | /audit-logs?userId=&action=&page=&size= | 审计日志(中间件自动埋点:登录/登出/增删改/审核/挑战等) | ## 设备配对 /agent | 方法 | 路径 | 鉴权 | 说明 | |---|---|---|---| | POST | /agent/pair-code | Bearer | 生成配对码(6 位,5 分钟一次性) | | POST | /agent/pair | 无(凭码) | 配对 {code,deviceName,os,version,publicKey(Ed25519 base64)} → {deviceId} | | GET | /agent/devices | Bearer | 设备列表(在线状态) | ## WSS 双通道 ### Agent 通道 `/ws/agent`(Ed25519 设备签名,无 JWT) | 方向 | 消息 | 说明 | |---|---|---| | C→S | `hello` | {deviceId,nonce,ts,sig(base64, 签名原文 nonce+`\|`+ts),version} | | S→C | `hello.ack` | {serverNonce,sessionId,serverTs,sig} | | C→S | `heartbeat`(10-30s) / S→C `heartbeat.ack` | 保活 | | S→C | `task.push` | 任务下发 {taskId,platform,accountId,title,content,tags,materialUrls(一次性签名直链),priority} | | C→S | `task.ack` | {taskId,accept,reason?}(accept→running) | | C→S | `task.result` | {taskId,status(success/failed),publishedUrl,receipts,error,finishedAt} | | S→C | `challenge.new` | 绑定扫码挑战 {challengeId,accountId,platform,kind,qrToken,qrUrl,prompt,expiresAt} | | C→S | `challenge.ack` / `challenge.solve` | 应答 / 完成(solve 后账号→active) | ### 浏览器通道 `/ws/browser?token=`(只读订阅) | 事件 | 说明 | |---|---| | `task.status` | {taskId,status,errorMessage,publishedUrls}(下发/执行/成功/失败实时推送) | | `agent.status` | {deviceId,online} | | `challenge.status` | {challengeId,status,accountId} | > 实测:任务下发延迟(approve→task.push)≈ 28.7ms(本机,硬指标 <300ms)。 ## 健康检查 | 方法 | 路径 | 说明 | |---|---|---| | GET | /health | 服务健康(db/redis 状态) |