ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Cal.com / cal.diy 平台 Atoms 本地联调实战指南:API v2、OAuth 客户端与 Examples App 全流程配置

Cal.com / cal.diy 平台 Atoms 本地联调实战指南:API v2、OAuth 客户端与 Examples App 全流程配置 Cal.com / cal.diy 平台 Atoms 本地联调实战指南API v2、OAuth 客户端与 Examples App 全流程配置【免费下载链接】cal.diyScheduling infrastructure for absolutely everyone.项目地址: https://gitcode.com/GitHub_Trending/ca/cal.diy本指南以 apps/api/v2/README-PLATFORM.md 为骨架系统讲解如何在本仓库中同时搭建 API v2 与 Platform Atoms 示例应用examples app的本地开发环境覆盖 Platform OAuth Client 与标准 OAuth 2.0 Client 两条授权链路的完整配置。读者在阅读完成后将能够独立完成从根环境变量、数据库种子、密钥生成到原子组件atoms构建与示例应用启动的整套联调流程并可在本地体验预订、可用性更新在 Web 应用与示例应用之间的实时联动。一、文档定位这套指南解决什么问题在开始动手前先厘清本指南在整个项目中的作用。仓库中 apps/api/v2/README.md 提供了 API v2 的基础本地开发说明但它的适用场景仅是“单独开发 API v2”。当你还需要用 Platform 的 atoms可定制 UI 组件用于把排期能力集成进自己的产品配合示例应用做本地联测时就需要转向本文档所描述的多服务联合开发流程。整个流程可以被拆解为三个层面的联动API v2Nest.js 服务提供业务接口位于 apps/api/v2Platform atoms 示例应用位于 packages/platform/examples/base是一个独立的 Next.js 应用默认运行在http://localhost:4321授权体系atoms 请求 API v2 时需要携带访问令牌而令牌的颁发依赖你在本地预置好的 OAuth 客户端——可以是 Platform 自有的 OAuth Client也可以是标准 OAuth 2.0 Client。从示例应用源码 packages/platform/examples/base/src/pages/_app.tsx 可以清晰看到两种模式的切换逻辑当NEXT_PUBLIC_OAUTH2_MODE true时页面使用CalOAuthProvider包装组件否则回落到使用CalProvider。这两者正是标准 OAuth 2.0 与 Platform OAuth Client 两条路径在前端的分界点。二、前置准备按 API v2 基础文档完成安装按照本文档的指引你首先需要打开 apps/api/v2/README.md完成其中除第 6 步Prisma 设置之外的全部步骤安装依赖在仓库根目录执行yarn install启动 DockerAPI v2 本地依赖 Docker启动 Docker 桌面即可启动 MailHog用于 v2 本地发送邮件命令为cd packages/emails yarn dx配置 api v2 环境变量将apps/api/v2/.env.example复制为apps/api/v2/.env并确保根目录.env与apps/api/v2/.env中的NEXTAUTH_SECRET值完全一致设置 License Key在数据库 Deployment 表写入一条licenseKey为00000000-0000-0000-0000-000000000000的记录并在apps/api/v2/.env中设置CALCOM_LICENSE_KEY00000000-0000-0000-0000-000000000000暂时跳过 Prisma 与种子此步yarn prisma generate/yarn prisma migrate dev/yarn db-seed在本指南的后半程第三部分的 API v2 收尾阶段再回来执行因为它与下方“平台 OAuth 客户端种子”的先后顺序有关。完成上述准备后我们进入 API v2 与示例应用共享环境变量的配置环节——这正是本文档区别于基础 README 的核心增量。三、配置共享变量平台 OAuth Client 与 OAuth 2.0 Client示例应用要访问 API v2必须先拥有一个授权客户端。本文档提供了两条等价路径你可以根据自己的偏好选择。3.1 路径一通过数据库种子自动创建客户端这是最省事的方式只需在环境变量中声明期望的客户端 ID 与密钥让种子逻辑自动写入数据库。第一步配置 Platform OAuth Client 变量在根目录.env中设置以下变量其中 id 与 secret 可以使用任意随机值SEED_PLATFORM_OAUTH_CLIENT_ID SEED_PLATFORM_OAUTH_CLIENT_SECRET然后将这两个值同步到示例应用的环境文件将packages/platform/examples/base/.env.example复制为packages/platform/examples/base/.env该文件预填了大量变量能显著降低配置成本把SEED_PLATFORM_OAUTH_CLIENT_ID的值复制到.env的NEXT_PUBLIC_X_CAL_ID把SEED_PLATFORM_OAUTH_CLIENT_SECRET的值复制到.env的X_CAL_SECRET_KEY。从 packages/platform/examples/base/.env.example 可以看到这两个变量正是示例应用以CalProvider模式即 Platform OAuth Client 模式运行时_app.tsx会读取的clientId与密钥来源。第二步生成 OAuth 2.0 Client 的哈希/明文密钥对Platform 需要再准备一个符合标准 OAuth 2.0 规范的客户端。它需要三个要素一个id、一个用于存储的哈希密钥hashed secret和一个用于客户端请求令牌的明文密钥plain secret。仓库为此提供了现成的生成脚本在apps/api/v2目录下执行cd apps/api/v2 yarn generate-secrets该脚本会基于 apps/api/v2/scripts/generate-secrets.ts 中calcom/platform-libraries导出的generateSecret()生成一对密钥并将结果写入apps/api/v2/.generated-secrets文件内容形如plain - PLAINTEXT_SECRET hashed - HASHED_SECRET其中PLAINTEXT_SECRET是明文、HASHED_SECRET是对应的哈希值两者一一对应不能混用。第三步填写根环境变量与示例应用环境变量在根目录.env中设置SEED_OAUTH2_CLIENT_ID SEED_OAUTH2_CLIENT_SECRET_HASHED其中CLIENT_ID可以随机但SECRET_HASHED必须是上一步生成出的哈希值。随后在packages/platform/examples/base/.env中设置NEXT_PUBLIC_OAUTH2_CLIENT_ID与 SEED_OAUTH2_CLIENT_ID 相同 OAUTH2_CLIENT_SECRET_PLAIN上一步生成的明文密钥注意两处变量名与取值语义的对应关系种子侧的_HASHED用于落库示例应用侧的_PLAIN用于发起authorization_code换令牌请求详见 README-OAUTH2.MD 的说明。3.2 路径二手工创建客户端如果你希望完全掌控数据库记录例如需要自定义 permissions、redirectUris 等字段可以跳过种子直接在数据库中手工插入记录。第一步创建 PlatformOAuthClient 记录在PlatformOAuthClient表中手工插入一条记录id 与 secret 可设随机值。参考 JSON 如下{ id: clxyyy21o0003sbk7yw5z6tzg, name: Acme, secret: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiQWNtZSAiLCJwZXJtaXNzaW9ucyI6MTAyMywicmVkaXJlY3RVcmlzIjpbImh0dHA6Ly9sb2NhbGhvc3Q6NDMyMSJdLCJib29raW5nUmVkaXJlY3RVcmkiOiIiLCJib29raW5nQ2FuY2VsUmVkaXJlY3RVcmkiOiIiLCJib29raW5nUmVzY2hlZHVsZVJlZGlyZWN0VXJpIjoiIiwiYXJlRW1haWxzRW5hYmxlZCI6dHJ1ZSwiaWF0IjoxNzE5NTk1ODA4fQ.L5_jSS14fcKLCD_9_DAOgtGd6lUSZlU5CEpCPaPt41I, permissions: 1023, logo: null, redirectUris: {http://localhost:4321}, organizationId: 1, createdAt: 2026-01-27 09:35:27.297, areEmailsEnabled: true, bookingCancelRedirectUri: null, bookingRedirectUri: null, bookingRescheduleRedirectUri: null, areDefaultEventTypesEnabled: true, areCalendarEventsEnabled: true }这份示例记录可供参考的字段包括permissions权限位掩码示例1023表示几乎全量授权redirectUris合法的回调地址集合示例只放行了http://localhost:4321areDefaultEventTypesEnabled/areCalendarEventsEnabled/areEmailsEnabled分别控制默认事件类型、日历事件与邮件能力是否启用。随后把 id 与 secret 复制到示例应用环境将packages/platform/examples/base/.env.example复制为packages/platform/examples/base/.env将 client id 复制到NEXT_PUBLIC_X_CAL_ID将 client secret 复制到X_CAL_SECRET_KEY。第二步生成并配置 OAuth 2.0 ClientOAuth 2.0 客户端同样需要 id 哈希/明文密钥对生成命令与上文相同cd apps/api/v2 yarn generate-secrets随后在packages/platform/examples/base/.env中把NEXT_PUBLIC_OAUTH2_CLIENT_ID设为随机 idOAUTH2_CLIENT_SECRET_PLAIN设为生成的明文密钥。第三步插入 OAuthClient 记录在OAuthClient表创建一条新记录id 与哈希密钥即上面生成/指定的值。文档特别强调redirectUri必须形如下方示例因为它指向示例应用的运行地址{ clientId: 1c70be53f35aa480a5e3146d361fd993d265e564d2d86a203df3adbd05186517, redirectUri: http://localhost:4321, clientSecret: 970db2cf14112013ba3a510b945294fef8737d42ee58c32031d2351692068ce7, name: atoms examples app oauth 2 client, logo: null, clientType: confidential, isTrusted: false, createdAt: 2026-01-27 09:35:26.731, purpose: test atoms examples app with oauth 2, rejectionReason: null, status: approved, userId: 10, websiteUrl: http://localhost:4321 }其中userId指向 10即种子用户adminexample.com。clientType: confidential表示机密型客户端适用授权码流程status: approved表示该客户端已通过审核、可直接使用。小贴士同一套手工创建的 OAuth 2.0 记录也可以复用 packages/platform/examples/base/README-OAUTH2.MD 中描述的自动方式即在根.env设置SEED_OAUTH2_CLIENT_ID与SEED_OAUTH2_CLIENT_SECRET_HASHED后于 prisma 目录执行yarn db-reset让种子逻辑为adminexample.com自动创建对应 OAuth 客户端。3.3 收尾回到 API v2 的 Prisma 与数据库种子两种路径配置完毕后回到 apps/api/v2/README.md 的第 6 步完成 Prisma 设置与数据库种子cd packages/prisma yarn prisma generate yarn prisma migrate dev yarn db-seed由于你已在上文把SEED_PLATFORM_OAUTH_CLIENT_ID、SEED_OAUTH2_CLIENT_ID等变量写入根.env种子脚本会一并创建 Platform OAuth Client 与 OAuth 2.0 Client 记录免去手工插库的繁琐。四、可选扩展Stripe 计费与 Apple Connect 日历4.1 StripePlatform 计费若需要在本地验证 Platform 计费能力请直接阅读 packages/platform/atoms/STRIPE.md 的专项教程。它是独立的计费联调文档涉及单独的账号与密钥这里不再展开。4.2 Apple Connect 日历 AtomE2E 专属如果你还希望测试 Apple Connect 日历 atom需要用苹果账号生成“App 专用密码”并设置如下变量ATOMS_E2E_APPLE_ID ATOMS_E2E_APPLE_CONNECT_APP_SPECIFIC_PASSCODE按 packages/platform/examples/base/.env.example 的注释这两个变量仅在 E2E 测试时需要仅运行示例应用可留空。4.3 选择授权模式最后示例应用支持两种授权模式由packages/platform/examples/base/.env中的NEXT_PUBLIC_OAUTH2_MODE决定置为true以标准OAuth 2.0 Client模式运行_app.tsx会选择CalOAuthProvider注释掉或设为false以Platform OAuth Client模式运行_app.tsx会选择CalProvider。五、启动全部服务atoms 构建、API v2 与示例应用5.1 构建 atoms本地开发模式atoms 默认以发布产物形式被引用本地联调时需要先切到开发构建模式cd packages/platform/atoms yarn dev-on yarn build-npm关于这两条命令文档给出了两条重要提醒dev-on会改变 atoms 的构建方式测试结束后务必执行yarn dev-off还原只要修改了任何与前端相关的内容例如 Booker 组件就需要重新执行yarn build-npm重建 atoms否则示例应用引用的仍是旧构建。5.2 启动 API v2推荐采用“先构建、再启动”的方式以规避 watch 模式下的抖动cd apps/api/v2 yarn dev:build yarn start文档解释了为何推荐这种方式如果同时运行着 cal web appv2 API 偶尔会因某些无关的构建日志文件变化而自动重启进而干扰示例应用。改为dev:buildstart后就不再受 watch 模式影响。5.3 初始化示例应用数据库并启动示例应用使用独立的 SQLite 数据库prisma/dev.db。首次运行或想重置数据时cd packages/platform/examples/base rm -f prisma/dev.db yarn prisma db push随后启动示例应用并访问http://localhost:4321cd packages/platform/examples/base yarn dev重置数据库这一步很关键如果沿用旧的 SQLite 而库中已有其他用户种子逻辑将不会为adminexample.com创建登录条目导致后续授权流程找不到对应用户。六、OAuth 2.0 模式的端到端验证若你在.env中将NEXT_PUBLIC_OAUTH2_MODE设为true可以按以下步骤完成一次完整的授权码流程验证启动 cal web app在仓库根目录执行yarn dev然后用任意用户登录本地运行的 cal web app若要用示例账号即adminexample.com需确保示例应用 SQLite 已按其初始化构造并访问 /authorize 地址基于前面配置的client_id与redirect_urihttp://localhost:4321拼接授权链接例如http://localhost:3000/auth/oauth2/authorize?client_id1c70be53f35aa480a5e3146d361fd993d265e564d2d86a203df3adbd05186517redirect_urihttp://localhost:4321statetexas如果你把localhost:3000映射到了app.cal.local也可以访问http://app.cal.local:3000/auth/oauth2/authorize?client_id1c70be53f35aa480a5e3146d361fd993d265e564d2d86a203df3adbd05186517redirect_urihttp://localhost:4321statetexas在页面中为该测试 OAuth 客户端授权。授权成功后浏览器会被重定向到localhost:4321?codeabc该路由会用授权码向 API v2 换取当前登录用户的 access token 与 refresh token并将其存入示例应用的 SQLite 数据库。验证联动效果完成以上步骤后示例应用即可直接使用。例如在示例应用中修改某个 availability改动会实时反映到本地 web app 中adminexample.com的可用性上。换一个角度理解这套流程OAuth 2.0 授权码交换的核心工作由示例应用侧的路由承担参见 packages/platform/examples/base/src/pages/api/refresh.ts其中同样以NEXT_PUBLIC_OAUTH2_MODE true判断走哪种刷新逻辑而令牌刷新 URL 由_app.tsx中的refreshUrl: /api/refresh统一交给 Provider 使用。七、常见问题与排错速查围绕整套流程把最容易踩坑的点集中列出现象原因处理方式示例应用请求 API 失败/401NEXTAUTH_SECRET在根.env与apps/api/v2/.env中不一致保证两处取值完全一致v2 API 无故重启与 cal web app 同跑时 watch 监听到无关构建日志变化改用yarn dev:buildyarn start脱离 watch 模式修改 atoms 前端代码不生效未重建 atoms 产物重新执行yarn build-npm示例应用登录后无adminexample.comSQLite 未重置或重复使用旧库执行rm -f prisma/dev.db yarn prisma db push后重启OAuth 授权跳转失败redirectUri与示例应用实际运行地址不一致确保 OAuthClient 记录的redirectUri为http://localhost:4321测试完本地 atoms 后影响正常构建忘了关闭 dev-on 模式执行yarn dev-off还原构建方式修改了 platform 系列依赖libraries/constants/enums/utils/typesAPI v2 未重建这些依赖重启 API v2也可另开终端执行yarn run dev:build:watch监听并自动重建另外若不需要 DockerAPI v2 还支持yarn dev:no-docker启动方式日常开发时也可用yarn dev快速起服务详见 apps/api/v2/README.md。八、总结从整体链路看本地的 Platform Atoms 联调环境本质上是**“一套环境变量 两类授权客户端 三个进程”**的编排根.env的四个种子变量SEED_PLATFORM_OAUTH_CLIENT_ID、SEED_PLATFORM_OAUTH_CLIENT_SECRET、SEED_OAUTH2_CLIENT_ID、SEED_OAUTH2_CLIENT_SECRET_HASHED决定了数据库里会有哪些授权客户端示例应用.env的NEXT_PUBLIC_X_CAL_ID/X_CAL_SECRET_KEY与NEXT_PUBLIC_OAUTH2_CLIENT_ID/OAUTH2_CLIENT_SECRET_PLAIN决定了它走CalProvider还是CalOAuthProvider最后用“构建 atoms → 启动 API v2 → 重置并启动示例应用”三步把所有进程拉起并在浏览器中通过/auth/oauth2/authorize完成授权闭环。按本文流程操作后你便拥有了一个可以同时开发 API v2、调试 atoms 组件并验证授权链路的最小本地闭环。若想进一步了解 API v2 的运行与测试命令单元测试、e2e、覆盖率以及 Guards 等代码约定可以继续阅读 apps/api/v2/README.mdOAuth 2.0 模式的补充细节见 packages/platform/examples/base/README-OAUTH2.MD。【免费下载链接】cal.diyScheduling infrastructure for absolutely everyone.项目地址: https://gitcode.com/GitHub_Trending/ca/cal.diy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进