news 2026/9/15 15:22:58

InsForge 共享 Schemas 开发指南:用 Zod 契约统一跨包 API 数据层

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
InsForge 共享 Schemas 开发指南:用 Zod 契约统一跨包 API 数据层

InsForge 共享 Schemas 开发指南:用 Zod 契约统一跨包 API 数据层

【免费下载链接】InsForgeThe all-in-one, open-source backend platform for agentic coding. InsForge gives your coding agent database, auth, storage, compute, hosting, and AI gateway to ship full-stack apps end-to-end.项目地址: https://gitcode.com/GitHub_Trending/in/InsForge

InsForge 是一个面向 Agent 编程场景的开源后端平台(BaaS),其仓库采用 monorepo 结构,包含backend(Express 服务端)、packages/dashboard(管理面板)、packages/ui(UI 组件库)等多个包。当同一个请求/响应/领域数据结构被多个包同时使用时,如何保证前后端契约一致、类型可信、演进可控,就成了工程质量的核心问题。本文基于仓库内维护者指南 .agents/skills/insforge-dev/shared-schemas/SKILL.md,系统讲解@insforge/shared-schemas包的设计定位、组织规范、变更流程与验证手段,并结合仓库真实源码剖析其实现细节。读完本文,你将掌握如何在 InsForge 中新增、修改和同步一个跨包共享契约,并能理解其背后的"以共享包为唯一真源(source of truth)"的工程原则。

一、Shared Schemas 包的定位与适用场景

packages/shared-schemas/是 InsForge 仓库中所有跨包数据契约的唯一来源(source of truth)。它对外发布为 npm 包@insforge/shared-schemas(当前版本1.2.0,见 packages/shared-schemas/package.json),由仓库的 npm workspaces(backendfrontendpackages/*,见 package.json)统一管理。

什么数据应该放进 Shared Schemas

根据 SKILL.md 的 Scope 定义,凡是满足以下任一条件的数据形状,都应定义在本包中:

  • 请求(request)载荷:如POST /api/auth/users的创建用户请求体;
  • 响应(response)载荷:如登录成功返回的{ user, accessToken, ... }
  • 跨包共享的领域形状(domain shape):如数据库表结构、备份配置、支付订阅等业务实体。

判断标准很简单:如果一个请求、响应或领域形状在 InsForge 的多个表面(backend 路由、dashboard 页面、MCP 工具、SDK)之间共享,就在这里定义它,而不要在包局部文件里复制同一份契约。SKILL.md 特别强调,该包不只服务于仓库内的 backend 和 dashboard 包,还被仓库之外的 InsForge 工具链(如 MCP 与 SDK 代码)消费,因此任何导出的名称和 schema 形状都属于公开契约面(public contract surface),而非内部重构目标。

包的基础设施

包内唯一运行时依赖是zod^3.23.8),构建产物输出到dist/,并通过exports字段暴露importtypes入口(packages/shared-schemas/package.json)。TypeScript 编译配置采用严格模式(strict: true)、ESM 模块、declarationdeclarationMap同时开启(packages/shared-schemas/tsconfig.json),保证消费方既能在运行时获得 Zod 校验器,也能在编译期获得精确的类型推导。

二、按领域组织的文件结构

SKILL.md 要求 schema 按领域(domain)组织,并遵循现有的*.schema.ts*-api.schema.ts双文件拆分模式。从 packages/shared-schemas/src/ 目录可以看到这套命名约定在仓库中的实际落地:

领域领域模型文件API 契约文件
数据库database.schema.tsdatabase-api.schema.ts
认证auth.schema.tsauth-api.schema.ts
AI 网关ai.schema.tsai-api.schema.ts
日志logs.schema.tslogs-api.schema.ts
函数functions.schema.tsfunctions-api.schema.ts
存储storage.schema.tsstorage-api.schema.ts
密钥secrets.schema.tssecrets-api.schema.ts
实时消息realtime.schema.tsrealtime-api.schema.ts
部署deployments.schema.tsdeployments-api.schema.ts
定时任务schedules.schema.tsschedules-api.schema.ts
支付payments.schema.tspayments-api.schema.ts
计算服务compute-services.schema.tscompute-services-api.schema.ts
分析posthog.schema.ts/posthog-config.schema.tsposthog-api.schema.ts

这一拆分的用意在于:*.schema.ts描述领域实体本身(如用户、表、备份记录),与传输层无关;*-api.schema.ts描述HTTP 层契约(请求体、响应体、查询参数、错误响应),依赖前者进行组合。例如auth-api.schema.ts中的createUserRequestSchema就是通过组合auth.schema.ts导出的emailSchemapasswordSchemanameSchema构建的(packages/shared-schemas/src/auth-api.schema.ts)。

index.ts 是公开 API 的"橱窗"

所有对外导出的符号都统一经过 packages/shared-schemas/src/index.ts 汇总。当前它 re-export 了 29 个 schema 模块,覆盖数据库、认证、存储、AI、日志、函数、实时、部署、支付、计算服务、分析、Web 抓取、错误码、仪表盘事件等几乎全部产品领域。SKILL.md 明确要求:保持index.ts与预期的公开 API 对齐——新增 schema 文件后必须在 index.ts 中导出,否则外部消费者无法引用。

三、核心工作规则:如何正确修改契约

3.1 先想清楚"这属于共享层吗"

修改任何请求/响应/领域形状前,先判断它是否跨包共享。若是,则必须定义在packages/shared-schemas/中;若否(仅在单个包内部使用),才允许留在包局部文件。严禁在 backend 或 dashboard 的局部文件中重复定义同一份契约,否则会出现"两处定义、一处修改、另一处悄然过期"的经典契约漂移问题。

3.2 用 schema 变更触发同步

SKILL.md 将 schema 变更视为一次"同步触发器",修改契约后必须逐项检查下游:

  1. backend 校验与响应使用:更新 backend/src/api/routes/ 下对应路由对请求体的校验和对响应体的序列化。实际仓库中,@insforge/shared-schemas已被 40+ 个后端路由文件与中间件引用,覆盖 auth、database、payments、storage、realtime、schedules、secrets 等领域(可从backend/src/api/routes/auth/index.routes.ts等文件的 import 语句确认)。
  2. dashboard 的服务、hooks 与 UI 假设:更新 packages/dashboard/src/ 下的 API service、数据获取 hooks 及组件中对字段形状的假设。dashboard 的 AI、Auth、Analytics、Datagrid 等特性模块均直接 import 共享包中的类型与校验器。
  3. 跨包 import 站点排查:在packages/*frontend/backend/全仓库范围内搜索该导出符号的所有引用点,确认没有遗漏。
  4. 评估下游影响:当变更涉及导出名称、schema 语义或载荷形状时,要明确指出对 MCP、SDK 或仓库外 InsForge 工具链的潜在破坏性影响。

3.3 破坏性变更要保守

SKILL.md 对破坏性变更(breaking change)的态度是"保守":如果确有必要,必须在交接说明(handoff)中显式标注。这一约束与包的公开契约定位直接相关——因为外部消费者(MCP、SDK)无法被本仓库的编译检查覆盖,静默破坏他们的解析逻辑是代价极高的错误。

3.4 永不使用any

SKILL.md 有一条硬性规定:共享契约中禁止使用 TypeScriptany类型。理由很直接:跨包边界上,类型必须是显式且可信的(explicit and trustworthy)。一旦某个字段被标为any,所有下游的类型检查在该字段上都会失明,契约的"可信任性"随之崩塌。仓库中的实际实现也严格遵循此规则,所有 schema 都基于 Zod 原始类型、枚举或组合对象构建,并大量使用z.infer<typeof ...>导出对应 TypeScript 类型。

四、从源码看契约设计的实际落地

4.1 数据库领域:约束的精细建模

packages/shared-schemas/src/database.schema.ts 是理解该包建模哲学的绝佳样本:

  • 列类型枚举ColumnType枚举覆盖stringdatedatetimeintegerfloatbooleanuuidjson八种常见列类型,同时columnSchematype字段用z.union([columnTypeSchema, z.string()])允许自定义类型字符串,兼顾封闭枚举与开放扩展;
  • 外键的复合键建模foreignKeySchema将外键建模为表级约束——一个约束实体包含一个有序的(sourceColumn -> referenceColumn)映射数组referenceColumns,最小长度 1,从而天然支持复合外键;注释明确说明"复合键是包含多对映射的单一实体,绝不跨列重复";
  • ON UPDATE 动作完整性onUpdateActionSchemaonDeleteActionSchema都接受CASCADESET NULLSET DEFAULTRESTRICTNO ACTION五种动作,注释解释了原因——Postgres 的 ON UPDATE 与 ON DELETE 支持相同的参照动作,introspection 可能返回SET NULL/SET DEFAULT,因此 schema 必须接受它们,否则从数据库反读元数据时会校验失败;
  • 约束即文档:每个 schema 上都有校验信息丰富的错误消息,如列名max(64)、表名非空、外键至少一个映射、迁移版本号必须匹配/^\d{1,64}$/(支持000120260418091500这种时间戳式版本)等,这些消息会直接透传给 API 调用方,构成用户体验的一部分。

4.2 认证领域:请求与响应契约的完备覆盖

packages/shared-schemas/src/auth-api.schema.ts 展示了 API 契约层的典型写法:

  • Discriminated Union 处理多方法登录createSessionRequestSchema使用z.preprocess将缺失/为空的method字段归一化为'password'(兼容旧客户端),再用z.discriminatedUnion('method', [...])passwordotp两种登录方式间做类型判别。preprocess 注释点明了设计意图:"缺席/空/undefined 的 method 视为传统密码流程;存在但非法的 method 仍会在判别联合中失败"(auth-api.schema.ts);
  • OTP 六位数字校验sixDigitCodeSchema(label)工厂函数生成/^\d{6}$/的正则校验,并为每个使用场景定制错误文案(OTP 验证码、重置密码码等);
  • PKCE 严格校验:OAuth 初始化与换码请求遵循 RFC 7636,code_challenge/code_verifier均限制长度 43~128 且必须匹配 base64url 字符集/^[A-Za-z0-9._~-]+$/,并特意用 snake_case 字段名对齐 OAuth 2.0 规范(auth-api.schema.ts);
  • SMTP 条件校验upsertSmtpConfigRequestSchemasuperRefine实现条件校验——当enabled: false时允许保存空连接字段(用户主动停用,字段无意义);启用时则强制 host、username、senderName 非空、senderEmail 合法,端口限定为 25/465/587/2525 四选一;
  • 最小暴露原则getPublicAuthConfigResponseSchema从 admin 响应中.omit({ allowedRedirectUrls, smtpConfig }),因为该路由无需认证,任何敏感字段(如内网 SMTP 主机名)都会泄露基础设施信息。注释中的约定值得注意:"新管理员专属字段默认落在authConfigSchema并自动进入 admin 响应;要公开某个字段,必须主动从.omit()中移除它——忘记思考时的默认值是安全的"(auth-api.schema.ts)。

这套"默认隐藏、主动暴露"的安全设计,正是共享契约层能够同时服务内部管理与外部客户端的关键。

4.3 类型推导与消费方式

每个 schema 文件末尾都会用z.infer导出强类型,如TableSchemaColumnSchemaCreateUserRequestCreateSessionResponse等。消费方(backend 路由、dashboard service)既可以 import 运行时校验器做请求体验证,也可以 import 类型做响应序列化约束,一套定义、两处受益。dashboard 侧的services/*.service.tshooks/use*.ts与组件层大量采用这种模式,例如 AI 特性模块的模型网关配置、Auth 页面的 SMTP 与 OAuth 配置表单。

五、变更后的验证清单

SKILL.md 给出了提交前必须通过的验证命令:

# 1. 构建共享 schemas 包,确认新契约可被编译为声明与产物 cd packages/shared-schemas && npm run build # 2. backend 全量类型检查,确认所有路由消费方无类型错误 cd backend && npx tsc --noEmit # 3. dashboard 类型检查,确认 UI 层消费方无类型错误 cd packages/dashboard && npm run typecheck

此外,若某个行为逻辑发生了变化,需要运行对应包的针对性测试(如 backend/tests/unit/ 下的单元测试)。SKILL.md 特别提醒:如果外部消费者(如 MCP、SDK)无法在本仓库内完成验证,必须如实说明,而不是暗示它们已被覆盖——这是对"事实准确"原则的工程化延伸,避免发布未经验证的契约。

在 monorepo 根目录下,也可以直接使用npm run build/npm run typecheck(通过 Turbo 编排所有 workspace,见 package.json)进行全仓统一校验。

六、实操场景:新增一个共享契约的完整流程

综合 SKILL.md 的工作规则与仓库现有模式,新增共享契约的推荐流程如下:

  1. 判定归属:确认新数据形状跨包共享。例如要给 dashboard 新增一个"工作区设置"实体,backend 路由与 dashboard 页面都需要它,则应放入共享层;
  2. 建文件:在packages/shared-schemas/src/下新建workspace.schema.ts(领域实体)与workspace-api.schema.ts(请求/响应契约),复用auth.schema.tsdatabase.schema.ts等既有模块导出的基础 schema 组合,保持类型显式、不加any
  3. 导出:在packages/shared-schemas/src/index.ts中追加export * from './workspace.schema.js';export * from './workspace-api.schema.js';(注意 ESM 下使用.js后缀);
  4. 后端接入:在 backend/src/api/routes/ 对应路由中 import 请求 schema 做safeParse校验,import 响应 schema 约束输出形状;
  5. 前端接入:在 packages/dashboard/src/ 的 service 与 hooks 中 import 同一份 schema,让请求构造与响应解析共用一套定义;
  6. 全局排查:在packages/*frontend/backend/下搜索该导出名,确认所有引用点已更新;评估对仓库外 MCP/SDK 的影响并显式说明;
  7. 验证:按上文清单依次执行npm run build(shared-schemas)、npx tsc --noEmit(backend)、npm run typecheck(dashboard),并运行受影响模块的测试。

七、总结

@insforge/shared-schemas是 InsForge monorepo 中连接 backend、dashboard 与外部工具链(MCP/SDK)的"契约中枢"。它通过 Zod 将每个跨包数据形状固化为"运行时校验器 + 编译期类型"的双重约束,用领域化的双文件结构(*.schema.ts/*-api.schema.ts)保持组织清晰,用"index.ts 即公开 API 橱窗"保证导出可控,用"默认隐藏敏感字段"的安全约定守护未认证端点,并用"禁止any+ 保守破坏性变更 + 强制全仓同步"三条铁律维持跨包边界的可信度。无论你是维护 backend 路由、dashboard 页面,还是计划扩展 InsForge 的 MCP/SDK 工具链,遵循 SKILL.md 中"以共享包为唯一真源"的原则,都能让每一次契约变更可追溯、可验证、可安全演进。

【免费下载链接】InsForgeThe all-in-one, open-source backend platform for agentic coding. InsForge gives your coding agent database, auth, storage, compute, hosting, and AI gateway to ship full-stack apps end-to-end.项目地址: https://gitcode.com/GitHub_Trending/in/InsForge

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 15:22:06

Zvec系列100问完结篇:回顾你的向量数据库知识体系

Zvec系列100问完结篇&#xff1a;回顾你的向量数据库知识体系 【免费下载链接】zvec A lightweight, lightning-fast, in-process vector database 项目地址: https://gitcode.com/GitHub_Trending/zve/zvec Zvec 是一款开源的进程内&#xff08;嵌入式&#xff09;向量…

作者头像 李华
网站建设 2026/9/15 15:20:22

文件夹同步备份全攻略:从手动复制到自动化方案

不知道你有没有经历过这样的场景&#xff1a;U盘里拷了一半资料&#xff0c;电脑提示“磁盘已满”&#xff0c;然后你开始删照片、清缓存&#xff0c;腾出空间后重新拖拽&#xff0c;结果搞到半夜发现漏了一个昨天刚改过的文档。或者更常见的——你在公司电脑上改完一份方案&am…

作者头像 李华
网站建设 2026/9/15 15:20:11

助听器怎么选?看场景不看参数的实战指南

1. 项目概述&#xff1a;这不是一场参数对比&#xff0c;而是一场“听觉适配”的实战检验“助听器哪个好&#xff1f;”——这句话背后藏着的不是技术参数的罗列&#xff0c;而是老人在菜市场听不清摊主报价时的尴尬&#xff0c;是年轻人在开放式办公室里漏掉关键会议指令的焦虑…

作者头像 李华
网站建设 2026/9/15 15:19:33

HTTP/HTTPS实战:请求头、状态码与数据包结构全解析

HTTP/HTTPS这套东西&#xff0c;说新不新&#xff0c;但真正能把它讲透、用到实战里的人真不多。我抓包三年多&#xff0c;前后端联调常见问题翻来覆去就那几个&#xff1a;请求头没带对、状态码看错、数据包结构理解偏差&#xff0c;尤其是热词里大家搜的“a标签下载视频请求头…

作者头像 李华
网站建设 2026/9/15 15:19:14

毕业论文写作全流程优化:从选题到AI检测的一站式解决方案

1. 毕业论文写作痛点与解决方案全景作为经历过本科、硕士、博士三轮论文洗礼的"老油条"&#xff0c;我深知毕业论文写作中的三大致命痛点&#xff1a;专业绘图耗时费力、排版格式反复修改、AI检测如履薄冰。最近实测了Paperzz全流程写作方案&#xff0c;这套系统从选…

作者头像 李华