23 KiB
API 与本地执行器参考
认证
除健康检查和登录接口外,业务接口要求:
Authorization: Bearer <session-token>
服务端会按以下顺序解析访问边界:
user → organization → workspace → project → permission
请求头中的 x-user-id、x-organization-id、x-workspace-id 和 x-project-id 只有在显式设置 AI_DRAMA_ALLOW_DEV_CONTEXT=1 时才可用于本地接口调试。正式部署不要启用该 bypass。
业务 API 分组
| 分组 | 主要接口 | 典型权限 |
|---|---|---|
| 认证与会话 | /api/auth/login、/api/auth/session、/api/auth/logout、/api/auth/password、/api/auth/sessions/* |
登录用户 |
| MFA 与企业身份 | /api/auth/login/mfa、/api/auth/mfa/*、/api/auth/sso/*、/api/system/identity/* |
MFA 管理或 system:settings:* |
| 租户上下文 | /api/context、/api/organizations/*、/api/workspaces/*、/api/projects/* |
按组织 / 工作区 / 项目角色 |
| 全局生产搜索 | `/api/search?q=&scope=workspace | project` |
| 用户通知中心 | /api/notifications、/api/notifications/:id、/api/notifications/read-all、/api/notification-preferences |
登录用户 / 当前组织 |
| 内容生产 | /api/production/catalog、/api/production/graph、/api/production/script/*、/api/production/bible、/api/production/shots/* |
script:edit、asset:edit、job:create |
| 资产与声音 | /api/assets/*、/api/assets/:assetId/versions/upload、/api/assets/:assetId/verify、/api/assets/:assetId/versions/:versionId/restore |
asset:edit、voice:edit |
| 生成任务 | /api/jobs、/api/jobs/:jobId/*、/api/adapters/dry-run |
job:create 或 queue:manage |
| 审片与交付 | /api/production/reviews/*、/api/production/qa/run、/api/production/deliveries/*、/api/exports/write |
qa:review、delivery:approve |
| 组织运营 | /api/usage、/api/billing、/api/organizations/:id/commercial、/api/organizations/:id/usage、/api/organizations/:id/usage/export、/api/organizations/:id/billing、/api/organizations/:id/quotas/:quotaId、/api/audit、/api/audit/export |
usage:view、billing:manage、quota:manage、audit:view |
| 模型中台 | /api/platform/models、/api/platform/models/register、/api/platform/models/:id/probe |
model:manage |
| 全局用户治理 | /api/system/users、/api/system/users/:userId、/api/system/users/:userId/revoke-sessions |
仅系统管理员 |
| 系统设置 | /api/system/config、/api/system/health、/api/system/readiness、/api/system/backups、/api/system/feature-flags、/api/system/notifications、/api/system/api-clients |
系统管理员 / 对应系统权限 |
未登录返回 401;已登录但没有作用域或权限返回 403。接口不会因为前端菜单隐藏就跳过后端检查。
全局生产搜索
GET /api/search?q=雷雨&scope=workspace&limit=40
GET /api/search?q=雷雨&scope=project&limit=40
搜索接口只在当前登录会话的组织、工作区和可访问项目集合内查询,支持项目、分集、剧本、镜头、资产、协作任务、生成任务和交付记录。scope=workspace 搜索当前工作区内可访问项目;scope=project 只搜索当前项目。返回结果包含 type、typeLabel、title、subtitle、status、targetTab 和目标作用域 ID,前端命令面板可以据此直接切换项目并跳转到对应生产页面。空查询返回空结果,不会返回未经筛选的目录数据。
搜索不会把连接器 endpoint、API key、客户交付令牌或本地存储绝对路径作为可搜索字段返回;跨组织、跨工作区或无项目访问权的关键词不会出现在结果中。
审计与合规中心
GET /api/audit?page=1&pageSize=25&query=&action=&targetType=&targetId=&result=&actorUserId=&from=YYYY-MM-DD&to=YYYY-MM-DD
GET /api/audit/:auditId
GET /api/audit/export?pageSize=500&format=json
GET /api/audit/export?pageSize=500&format=csv
审计列表由服务端分页并返回 auditLog、pagination、facets 和 scope。org_owner / org_admin 默认只能看当前组织;其他拥有审计读取权限的角色只能看当前工作区 / 项目及组织级事件;系统管理员获得全局视图。查询参数只负责缩小范围,不能扩大当前作用域;跨组织、跨工作区或跨项目筛选会返回 403。详情接口同时返回同一对象的关联审计和可关联的账号安全事件。导出支持 JSON 和 UTF-8 CSV,并复用相同的服务端权限与筛选条件。
用户通知中心与组织级偏好
通知中心是用户在当前组织、当前工作区内的收件箱,不等同于管理员配置的邮件或 Webhook 投递渠道。通知事件由服务端按组织成员、工作区/项目成员和事件类型计算收件人,前端不能扩大收件范围。
GET /api/notifications?limit=60&unreadOnly=1
PATCH /api/notifications/:notificationId # { "read": true | false }
POST /api/notifications/read-all
GET /api/notification-preferences
PATCH /api/notification-preferences/:category # { "enabled": true | false }
limit 会被服务端限制在 1-200;unreadOnly=1 只改变列表,不改变返回的 unreadCount。单条已读/未读和“全部已读”都只作用于当前用户、当前组织以及当前工作区可见的通知,跨用户、跨组织或不属于当前作用域的通知返回 404。
通知偏好按“用户 + 组织 + 类别”保存,切换组织后使用独立配置。当前类别包括:生成任务、审片、交付、协作任务、组织访问、用量配额和系统通知。服务端在创建用户通知前真正检查偏好,关闭某类后不会只在前端隐藏,而是不会写入该用户的收件箱;重新开启只影响后续事件,不会自动补发历史消息。
项目协作任务
协作任务是可分派、可追踪的项目记录,不等同于由生成任务或审片状态推导出来的 /api/work-items 待办。任务只能落在当前组织 / 工作区 / 项目作用域内,并保存标题、说明、类型、优先级、负责人、截止时间、关联页面、状态、完成时间和审计记录。
GET /api/tasks?status=all&assignedTo=me&limit=100
POST /api/tasks
PATCH /api/tasks/:taskId
task:manage 可以创建、分派和编辑任务;task:complete 的成员只能更新自己负责任务的状态,不能修改标题、负责人、优先级或截止时间;task:view 只能读取当前项目任务。任务分派会按用户通知偏好创建站内消息,任务状态变更和跨组织访问也会写入权限边界和审计流。项目归档后任务写操作返回 409 project_archived。
系统管理员配置的 /api/system/notifications 仍负责组织级本地日志/Webhook 渠道和投递审计;Webhook 默认只允许投递到本地私有 HTTP 地址,云端或付费节点不会被平台自动启用。
项目生命周期与只读归档
项目是可审计的生产边界,不是只有名称和状态的目录项。创建项目时会持久化 template_id,并立即初始化系列、第一季、试播集和一个 starter shot;新项目默认处于 draft。
PATCH /api/projects/:projectId
POST /api/projects/:projectId/lifecycle
生命周期动作包括:pause、resume、activate、submit-review、archive、restore。归档前服务端会检查 queued、running 和 blocked 生成任务;存在未完成任务时返回 409 project_has_active_jobs。归档会保存 archived_at、archived_by 和 archived_from_status,恢复时回到归档前状态。
归档项目仍可读取生产图谱、任务历史、审计和交付资料,但剧本、资产、声音、生成、QA、交付审批等写操作由后端统一返回 409 project_archived。前端项目工厂只负责呈现可用操作,不能替代服务端权限边界。
系统生产就绪度与数据库快照
系统管理员可读取部署边界和当前运行时状态:
GET /api/system/health
GET /api/system/worker
GET /api/system/readiness
GET /api/system/backups
POST /api/system/backups
/api/system/health 返回数据库中的服务探针、Runner 状态、队列深度和最近心跳;/api/system/worker 返回本地 Worker 的租约、并发、心跳年龄和队列告警。管理概览直接使用这些服务端结果,组织管理员只能看到后端允许的健康范围,不能通过前端隐藏绕过权限。
/api/system/readiness 会明确区分当前激活运行时与目标 provider:业务数据库当前返回 node:sqlite,PostgreSQL、Redis、S3-compatible 对象存储只有在对应 PLATFORM_* 环境变量存在时标记为“已配置”,不会把 compose 注入误报成已经完成业务迁移。POST /api/system/backups 使用 SQLite VACUUM INTO 创建 data/backups/ 下的快照,并写入 system.database.backup_created 审计事件;接口不提供在线恢复,恢复必须经过停机审查和人工确认。
商业运营、席位与配额
组织管理员或组织所有者可以读取当前组织的套餐、席位预留、工作区配额和本月用量:
GET /api/organizations/:organizationId/commercial
GET /api/organizations/:organizationId/commercial/export
PATCH /api/organizations/:organizationId/billing
PATCH /api/organizations/:organizationId/quotas/:quotaId
PATCH /api/organizations/:organizationId/cost-centers/:costCenterId
billing 更新接受 planName、billingCycle(monthly / quarterly / annual)、currency、baseFee、seatUnitPrice、storageUnitPrice、clipUnitPrice、seatLimit、storageGb、monthlyClipQuota、quotaWarningPercent、localRunnerOnly 和 cloudConnectorsRequireApproval。服务端会阻止席位低于活跃成员加待处理邀请、片段额度低于本月已用量、存储额度低于已记录用量的修改,并记录 billing.account.updated 审计事件和可查询的 billing_account_events 变更记录。
工作区配额不能超过组织套餐上限,也不能低于已用量;违反时分别返回 409 quota_above_plan 或 409 quota_below_usage。普通成员即使知道接口路径,也会收到 403 permission_denied,前端菜单隐藏不构成权限边界。
商业运营响应额外包含 quotaWarnings、costCenters、按工作区拆分的 costCenterDetail、billingHistory 和 usageTrend。usageTrend 是最近 31 天按自然日聚合的数组,每项为 { day, units, estimatedCost, events };没有事件的日期不会伪造为零值。成本中心预算由 billing:manage 控制,导出接口返回可归档的完整 JSON,不会把云端或付费连接器伪装成本地成本。
事件级用量中心用于账务核对、配额追踪和成本归属:
GET /api/organizations/:organizationId/usage?page=1&pageSize=25&from=YYYY-MM-DD&to=YYYY-MM-DD&workspaceId=&projectId=&userId=&kind=&unitName=&costCenter=&query=
GET /api/organizations/:organizationId/usage/export?format=json&from=YYYY-MM-DD&to=YYYY-MM-DD&workspaceId=&projectId=&userId=&kind=&unitName=&costCenter=&query=
GET /api/organizations/:organizationId/usage/export?format=csv&from=YYYY-MM-DD&to=YYYY-MM-DD&workspaceId=&projectId=&userId=&kind=&unitName=&costCenter=&query=
明细接口返回 items、summary、pagination 和 facets。每条事件包含时间、工作区、项目、操作者、事件类型、计量单位、估算成本、成本中心和元数据;筛选、分页和导出都在服务端执行。组织管理员可查看本组织范围,普通成员即使直接调用路径也会收到 403;成本中心和配额预警在管理台可以回跳到同一组明细筛选条件。
组织账单台账用于把套餐、席位、存储、片段和事件级本地计量固化为可审计的账期快照:
GET /api/organizations/:organizationId/invoices?status=&query=&page=1&pageSize=25
GET /api/organizations/:organizationId/invoices/:invoiceId
POST /api/organizations/:organizationId/invoices/generate
POST /api/organizations/:organizationId/invoices/:invoiceId/status
GET /api/organizations/:organizationId/invoices/export?format=json|csv&status=&query=
只有拥有 billing:manage 的组织管理员或组织所有者可以生成账单、修改账单状态和编辑计价参数;拥有 usage:view 的角色可以读取账单台账。普通成员直接调用接口也会收到 403 permission_denied,跨组织读取会收到 403 organization_forbidden。
generate 默认按组织套餐周期生成当前账期草稿,也接受成对的 periodStart / periodEnd、taxRate 和 dueDays。同一组织同一账期通过数据库唯一约束保证幂等,重复生成返回原账单而不会覆盖原快照。账单状态机为 draft -> issued -> paid,issued 可以转为 overdue 或 void,overdue 可以补记为 paid;已支付和已作废账单不可逆修改。每次生成和状态变更都会写入账单事件及组织审计日志,详情接口会返回 lines 明细。
套餐接口的计价字段包括 baseFee、seatUnitPrice、storageUnitPrice 和 clipUnitPrice,默认值为 0;本地环境不会凭空产生收费。生成账单时会保存套餐、席位、工作区存储、片段用量、成本中心和税率快照,JSON/CSV 导出可用于后续财务系统适配。
组织邀请生命周期
组织管理员或拥有 organization:members:invite 的角色可以管理成员邀请:
GET /api/organizations/:organizationId
GET /api/organizations/:organizationId/members
POST /api/organizations/:organizationId/invitations
POST /api/organizations/:organizationId/invitations/:invitationId/resend
POST /api/organizations/:organizationId/invitations/:invitationId/revoke
GET /api/invitations/preview?token=:token
POST /api/auth/register
创建或重发邀请时,服务端只在当前响应返回一次性 inviteToken 和 acceptUrl;数据库保存的是令牌哈希和短提示,不保存明文令牌。邀请默认 7 天过期,过期邀请不会继续占用席位。重发会替换令牌哈希,使旧注册链接立即返回 404 invitation_not_found;撤销会清空令牌哈希、返回 revoked,并释放待入组席位。未登录预览仍可读取邀请范围,但注册时会再次校验令牌、邮箱和有效期。
邀请角色必须匹配目标层级:不传 workspaceId 时只能使用组织角色 org_member / org_admin;传 workspaceId 时只能使用工作区角色 producer / writer / art_director / voice_editor / reviewer;同时传 workspaceId 与 projectId 时只能使用项目角色 project_editor / project_viewer。项目级邀请接受后会自动建立 project_guest 工作区成员身份和 access_mode=project-only,不会把项目角色升级为工作区制片,也不会展示工作区其他项目;组织所有者不能通过普通邀请授予。
普通成员调用组织邀请接口返回 403 permission_denied;重复邀请同一邮箱返回 409 invitation_already_pending,已是组织成员的邮箱返回 409 invitation_recipient_already_member。
MFA
POST /api/auth/login在账号启用 TOTP 后返回mfaRequired和短时challengeToken,不创建正式会话。POST /api/auth/login/mfa使用challengeToken + code完成二次验证并创建 Bearer session;挑战 5 分钟过期,连续错误 5 次锁定。GET /api/auth/mfa、POST /api/auth/mfa/setup、POST /api/auth/mfa/enable、POST /api/auth/mfa/setup/cancel、POST /api/auth/mfa/disable只接受真实浏览器 session。- MFA 密钥使用 AES-GCM 加密;生产部署应设置独立的
AI_DRAMA_MFA_ENCRYPTION_KEY,不要依赖默认开发密钥。
企业身份中心
系统管理员可通过以下接口管理身份控制面:
GET /api/system/identity
PATCH /api/system/identity/policy
POST /api/system/identity/providers
PATCH /api/system/identity/providers/:providerId
POST /api/system/identity/providers/:providerId/probe
POST /api/system/identity/directory-syncs
PATCH /api/system/identity/directory-syncs/:directoryId
POST /api/system/identity/directory-syncs/:directoryId/rotate-token
GET /api/auth/sso/providers
GET /api/auth/sso/start?providerId=:id&returnTo=/
GET /api/auth/sso/callback
POST /api/auth/sso/redeem
OIDC 已实现 Authorization Code + PKCE、state/nonce 一次性状态、ID Token 签名校验(JWKS)、claims 映射、按 Provider 绑定组织/工作区、自动创建成员和正式 Bearer session。回调不会把 session token 放进 URL,而是跳转到前端兑换 60 秒一次性票据;票据重放返回 401。如果用户启用了 MFA,票据兑换会返回现有 MFA challenge/enrollment challenge,再复用 /api/auth/login/mfa 或 /api/auth/mfa/enroll/*。
提供商配置只保存 clientSecretRef 或 idpCertRef 环境变量引用,不保存 Client Secret 或 SAML 证书正文。OIDC 已实现 discovery 探测、Authorization Code + PKCE、state/nonce、JWKS 签名校验和一次性 SSO ticket。SAML 已实现 HTTP-Redirect AuthnRequest、持久化 RelayState、HTTP-POST ACS、签名/Audience/时间窗口/InResponseTo 校验、组织/工作区入组、MFA 和一次性 SSO ticket;ACS 不接受前端提交的用户身份。
全局用户治理
系统管理员可以跨组织查询用户、查看组织/工作区/项目归属、MFA 状态、最近登录和活跃会话:
GET /api/system/users?query=&status=&limit=100
POST /api/system/users
GET /api/system/users/:userId
PATCH /api/system/users/:userId # status: active | suspended
POST /api/system/users/:userId/reset-password
POST /api/system/users/:userId/reset-mfa
POST /api/system/users/:userId/memberships
POST /api/system/users/:userId/revoke-sessions
系统管理员可以手动创建账号并一次性取得初始密码、重置密码或 MFA、授予/移除系统管理员身份,并将用户加入指定组织、工作区和项目。加入关系会经过组织席位、层级归属和角色 scope 校验。停用或安全重置会立即撤销该用户的全部 Bearer session;不能停用当前系统管理员,也不能停用最后一个系统管理员或组织唯一所有者。所有状态变化、密码/MFA 重置、归属变化和强制会话撤销都会写入审计日志。组织管理员仍只能访问本组织成员接口,不能读取全局目录。
生产部署至少应设置:AI_DRAMA_SESSION_SECRET、AI_DRAMA_MFA_ENCRYPTION_KEY、AI_DRAMA_OIDC_STORAGE_KEY、AI_DRAMA_FRONTEND_ORIGIN 和每个 Provider 引用的 Client Secret 环境变量。默认回调地址为 http://127.0.0.1:8787/api/auth/sso/callback,多实例部署请使用固定的 AI_DRAMA_OIDC_REDIRECT_URI。
SCIM 目录由管理员创建后得到一次性 Bearer 令牌;令牌只保存 SHA-256 哈希。启用目录后,使用该令牌调用:
GET /scim/v2.0/:directoryId/Users
POST /scim/v2.0/:directoryId/Users
PATCH /scim/v2.0/:directoryId/Users/:userId
DELETE /scim/v2.0/:directoryId/Users/:userId
SCIM 用户只会进入该目录绑定的组织,停用操作会同时停用组织成员资格,不能跨组织写入。
资产文件版本会登记 fileName、mimeType、fileSize 和 contentSha256。POST /api/assets/:assetId/versions/upload 写入新的真实文件版本,POST /api/assets/:assetId/verify 重新读取文件并比较哈希/大小,验证结果写入审计日志;GET /api/assets/:assetId/content 返回 ETag,便于下游缓存和交付校验。
Worker API
本地 API 启动时会自动启动本地 Worker;不需要额外启动第二个 Worker 进程。Worker 会:
- 使用数据库租约
leased_by/leased_at领取任务,避免多个 Runner 重复执行。 - 受
AI_DRAMA_WORKER_CONCURRENCY限制,默认并发为2,最大为8。 - 按
AI_DRAMA_WORKER_POLL_MS轮询,默认1200ms。 - 只领取
status=queued、依赖已完成、连接器status=ready且cost_mode=local的任务。 - 连接器异常时保留 attempt、错误信息、审计事件和通知事件;未达到
max_attempts会按指数退避自动重新排队,超过上限才保持failed。 - 发现
leased_at超时的 running 任务时会回收租约,按最大尝试次数重新排队或标记失败,避免 Worker 进程退出后任务永久卡住。 - 心跳、队列最老任务等待时长和告警级别会写入 Worker 状态,管理员可以批量重试或取消任务。
GET /api/admin/queue
POST /api/admin/queue/batch # action: retry | cancel | priority
GET /api/system/worker
POST /api/system/worker/dispatch
GET /api/system/worker 返回 workerId、healthStatus、心跳年龄、过期阈值、并发数、轮询间隔、队列深度、队列告警、当前执行数、最近领取 / 完成 / 失败 / 回收 / 重试时间和最后错误。POST /api/system/worker/dispatch 用于管理员立即触发一次领取,适合排障和演示。
可选环境变量:
AI_DRAMA_WORKER_ENABLED=1
AI_DRAMA_WORKER_ID=local-worker-<host>
AI_DRAMA_WORKER_POLL_MS=1200
AI_DRAMA_WORKER_CONCURRENCY=2
AI_DRAMA_WORKER_LEASE_MS=300000
AI_DRAMA_WORKER_STALE_MS=30000
如果设置 AI_DRAMA_WORKER_ENABLED=0,任务不会自动执行,后台仍会显示 Worker 已暂停。
POST /api/jobs/:jobId/run 允许管理员或拥有 job:create 的角色手动执行任务;如果请求到达时任务已经被本地 Worker 完成,服务端返回现有结果并带 idempotent: true,避免手动按钮与自动 Worker 竞态导致重复生成。
模型协议适配器
模型连接器在模型中台注册,密钥只保存为环境变量名,不保存密钥本身:
{
"label": "本地单画面图片服务",
"endpoint": "http://127.0.0.1:7860/api/generate/image",
"kind": "http-json",
"capability": ["text-to-image", "single-frame"],
"costMode": "local",
"authEnv": "LOCAL_IMAGE_TOKEN",
"protocol": {
"healthRoute": "health",
"routes": { "image": "generate" },
"models": { "image": "qwen-image-local" }
}
}
支持三种协议:
http-json:向endpointPOST 完整生产合同和execution元数据。openai-compatible:按image、video、tts、asr、chat选择路由和模型;图片请求固定发送n: 1。comfyui:向prompt路由提交工作流,作为可选桥接,不是默认生产链路。
图片任务会检查响应中的 data、images 或 outputs 数组,必须恰好返回一项;返回多张、拼图、分屏或 contact sheet 的结果会进入失败状态,不会进入后续视频链路。
外部或混合成本连接器默认需要管理员显式审批;本地 Worker 不会自动领取 mixed / cloud 任务。
启动与验证
cd /Users/xz/Documents/daima/ai短剧/ai-drama-platform
npm run api
npm run dev
验证顺序建议:
npm run build
npm run smoke:identity
npm run smoke:system-users
npm run smoke:commercial-ops
npm run smoke:oidc
npm run smoke:tenant
npm run smoke:creator-suite
npm run smoke:ops
npm run smoke:production-catalog
npm run smoke:worker
npm run smoke:all
多个 smoke 会写入同一个 SQLite 文件,应顺序执行。