# 开发规范

新应用默认使用标准 `plugin.json`；旧 `aidc.app.json` 继续支持。Apps 与 OpenAI Plugin 的包、UI、默认 AIDC 登录和可选 OAuth 规范见 [Plugin 兼容](plugins.md)。

AIDC 内部与客户开发者共用的一套规范。AIDC 成员在 aidc-cloud 仓库里开发时，完整版在 Skill `aidc-development`（`.claude/skills/aidc-development/`）与 `docs/api-standards.md`；这里是面向所有开发者的摘要。

## 1. 先 API + CLI，先智能体后 UI

每个能力先有 API（契约化、可发现），再有 CLI（API 的薄封装），最后才是 UI——UI 只调同一套 API。设备能力（摄像头、麦克风）在浏览器 SDK 里实现，但凡涉及服务端的一步（票据、模型、数据）仍然走 API。

## 2. 给智能体用的形态

- API 永远返回信封：`{ok:true, data, meta}` 或 `{ok:false, error:{code, message, details}, meta}`；错误码稳定、可枚举（见 [OpenAPI](https://www.ai-dc.ai/developer/openapi.json)）。
- CLI 每条命令都有 `--json`，stdout 不是终端时默认 JSON；进度提示走 stderr。
- 永不交互；缺参数直接报错并说明怎么补。
- 退出码：`0` 成功、`1` 一般错误、`2` 参数、`3` 未登录、`4` 无权限、`5` 不存在、`6` 冲突、`7` 限流 / 额度、`8` 上游故障。

## 3. 幂等与 dry-run

- 发布是幂等的：版本内容寻址（同样的文件 = 同一个版本），通道晋升是「把指针设为版本 N」。重试不会产生重复数据。
- 有副作用的操作都支持预演：API 带 `x-aidc-dry-run: true`，CLI 加 `--dry-run`，返回 202 与将要发生的计划。

## 4. 复用，不重复造轮子

登录、会话、Key、计费、限流、模型上游、实时转写、Markdown 渲染……平台都已经有一份。应用里需要这些能力时调 SDK，不要自己再写一套；平台内部开发时查 `aidc-development` 的复用登记表。

## 5. 依赖：站在成熟基础设施上

- 公认的基础设施放心用，不要自研替代品：ffmpeg、PostgreSQL、Redis、浏览器原生的 `getUserMedia` / `MediaRecorder` / WebRTC / Web Audio / canvas、OpenAI 兼容协议。
- 不成熟的第三方库（单人维护、长期无发布、依赖树深）默认不引入；确需引入时钉版本、包一层适配。
- 浏览器端只从 `cdn.jsdelivr.net` / `cdnjs.cloudflare.com` 加载第三方脚本，写进清单的 `cdn`。

## 6. 文档与版本

- SDK 与 CLI 同步发版（SemVer），变更记在 [更新记录](changelog.md)；浏览器 SDK 的路径带大版本（`/developer/sdk/v1/`），破坏性变更才升 `v2`，旧版继续可用。
- API 在 `/api/v1/**` 内不做破坏性变更。

## 7. 安全边界

- 开发者 Key（`aidc-dk-…`）只放在服务端 / CLI / 环境变量里，绝不写进前端代码。浏览器里的应用用平台注入的应用票据（`aidc-at-…`，短命、只能调清单里声明的模型与数据集）。
- 客户应用跑在 CSP 沙箱里（不透明源，拿不到访客的登录态），只能凭票据调 API。
- 数据只出聚合：数据集的固定报告不返回明细行。

## 8. 界面

- 所有应用用[界面 SDK](ui.md)：页面引 `/developer/sdk/v1/ui.css`，按钮、表单、卡片、表格、对话框用它的 `aidc-*` 类；应用自己的 CSS 只写版面与业务特有的东西。
- 主按钮实心黑，信号橙只用于加载、选中与需要注意的状态；等待态用 `//` 加载动效，不用圆环 spinner。
- 确认、输入、提示用 `ui.confirm` / `ui.prompt` / `ui.toast`，不用 `window.confirm` / `prompt` / `alert`。
- React 项目用 shadcn/ui 与 `@aidc` 注册表（[AIDC UI](https://www.ai-dc.ai/asset/ui)），令牌与 HTML 应用同一套。

## 9. 一个 SDK 由什么组成

AIDC 的每个 SDK 都是同一副骨架（AIDC 内部的完整清单与自动检查在 `aidc-development` 的 SDK 标准里）：

| 部分 | 在哪里 |
| --- | --- |
| API（有服务端的一步时） | `/api/v1/**`，契约进 [OpenAPI](https://www.ai-dc.ai/developer/openapi.json)；纯前端能力的契约是机器可读的登记表（如界面 SDK 的 `ui.json`） |
| CLI | `aidc <命令组> <动作>`，`--json`、`--dry-run`、稳定退出码 |
| 浏览器模块 | `aidc.js` 里的一个具名导出（`import { ui } from "/developer/sdk/v1/aidc.js"`） |
| 文档 | 一页 Markdown（每页都有 `.md` 原文给智能体），进总览表、`llms.txt` 与 Agent Skill |
| 清单登记 | `aidc.app.json` 的 `sdk`；部署时静态分析，用了没登记的拒收 |
| 版本 | 与其余 SDK 同步发版，记在[更新记录](changelog.md) |

## 10. 每个应用一张应用卡片

平台按清单、部署时的静态分析、通道与使用日志给每个应用自动生成[应用卡片](app-card.md)（负责部门、版本、用了哪些 SDK、是否连数据库、读写哪些数据、对外能力与依赖、访问范围、近 7 天使用），开发者不手写，但要让它是对的：

- 清单写 `owner`（部门 / 岗位或智能体 / 负责人）与一句话 `summary`；
- `sdk`、`semantic`、`streams`、`models` 如实登记（用了没登记的部署拒收，登记了没用到的卡片上会标出来）；
- 想被别的应用或[工作流](workflow.md)用，就把可以对外的查询 / Action 写进 `exports`；
- `version` 每次改动都升（SemVer）。

查看：应用顶栏「卡片」、`appCard()`、`aidc app card`、`GET /api/v1/developer/apps/{命名空间}/{slug}/card`。

## 11. 成本与资源：不在不知情的状态下增加账单

- **先算账，再开**：按量计费的东西（函数时长、流量、模型 token、实时转写、外部 API）上线前估一下「次数 × 单价」。
- **开完就关**：临时开的服务、后台进程、测试用的 Key、测试数据、定时任务，用完就关掉、吊销、删除。
- **每个应用都有上限**，清单 `limits` 不写就用缺省值：计算分钟 **2000 / 月**（实时连接挂着、工作流运行、模型调用的时长）、每天 100 万 token、每 IP 每分钟 30 次请求、每天 100 场实时转写、每天 20 封通知。用完返回 `429 quota_exhausted`，下月 / 次日恢复。调高就是允许它花更多钱，部署时会告警。用量：`aidc app usage <slug>`。见[发布 SDK](publish.md#资源上限与成本告警)。
- **长连接只在有人看的时候开**：SDK 的实时连接在页面隐藏 1 分钟后自动断开、切回来续上（不丢不重）；不要用 `setInterval` 轮询服务端（部署时告警）。

## 12. 触发优先于定时

- 数据一变才需要做的事，用[数据流](connect.md) + [工作流](workflow.md)的 `trigger.change`（`when` 条件、`cooldown` 冷却）：没变化时零成本、不写 cron。
- 定时（`trigger.schedule`）只给「时间本身就是条件」的事：日报、月底对账、数据该来却没来的看门狗。**每天一次是常态**。
- 频率分级：比每 5 分钟还密拒收；5 分钟到 1 小时一次是高频，**部署时一定告警**（带上每月次数与预计的计算分钟）；1 小时到 1 天提示次数；每天及以上正常。
- 告警、提醒用工作流的 `notify` 步骤发邮件：收件人必须是本公司账号，同样的通知在冷却时间内只发一次，每天有上限，每一封发没发出去都有记录。

## 13. 产品自提升

我们根据每次开发遇到的问题持续改进规范：遇到新问题、或者发现规范少了一条判断，就在同一次改动里把它变成一条规则或一个自动检查（测试、部署校验），并记进问题账本——同样的问题不出第二次。提升本身也守第 11 条：不为提升去开资源，要开就先算账、用完就关。
