Repository navigation
Description
repo:cloud#2 · os-zhuang · session_0123kRqqdpAJWYMgsgdAJX4G (filed on the maintainer's direction, handed off from the #27108 cloud-assessment thread)
Filing gate: ③ maintainer-directed, and ④ the cross-repo parent of its children. The maintainer, in the cloud project thread on 2026-10-28 (verbatim, not translated): 「钉钉这种不支持标准API的,有没有可能我们封装一层中转的微服务,按照标准协议」 (16:03Z) · 「用户映射、身份认证,这个属于单独的需求,能否也可以是另外一套中转服务」 (16:05Z) · 「我说的只是把钉钉作为例子,还会有企业微信,飞书等,你认为是中转服务的方式好,还是开发具体插件的方式好。」 (16:10Z, answered: bridges) · 「我创建了 bridges 仓库,你可以初始化,然后刚才讨论的问题立专题卡」 (16:15Z) · 「这个应该是单独的专题卡吧」 (16:16Z). And on the #27108 decision card 「插件专题 #27108 在中转方案之后怎么处理?」 the maintainer chose 「M1 做完,其余冻结」 (16:18Z). ⛔ Not a claim. ⛔ No domain:*: children span objectstack (server), cloud and objectstack-ai/bridges; triage sets each child's lane.
Dedupe: bridge relay DingTalk WeCom Feishu webhook messaging channel OIDC SCIM on objectstack → 0 hits (open or closed). Related, not duplicates: #27108 (code plugins), #27287 (SDK contract, frozen by this ruling), #27293 (zero-code connectors — this epic's action side reuses it).
维护者速读
钉钉、企业微信、飞书这类不讲标准协议的套件,不再做成代码插件,而是走独立的「中转服务」(bridge):平台只讲标准协议,bridge 负责把标准协议翻译成厂商私有 API。平台补齐几个通用接口一次(出站 webhook 消息通道、入站 webhook、OIDC 登录、SCIM 通讯录),以后每接一家只是多一个 bridge,平台不改。bridge 放在新仓 objectstack-ai/bridges(公开、Apache-2.0,已初始化 80b4abd),每家一个包、各自发版;同一份代码既跑我们托管的多租户实例,也出 Docker 镜像给私有部署客户内网自部署。连带裁决:#27108 只做完 M1,M2–M5 与 SDK 冻结;托管 Cloud 不加载代码插件。
Decisions this epic carries
| # | Decision | Effect |
|---|---|---|
| 1 | Vendor suites without a standard API (DingTalk, WeCom, Feishu, and the like) integrate through bridges, not code plugins. | #27108 ruling 6471792611 item 3 (plugin-dingtalk as the first resident of objectstack-ai/plugins) is withdrawn; DingTalk is this epic's first bridge. |
| 2 | #27108: M1 finishes; M2, M3, M4, M5 and the SDK contract are frozen until a paying customer asks for third-party code distribution. | #27124, #27125, #27284, #27285, #27287 frozen (recorded on #27108). M1 #27123 continues unchanged. |
| 3 | Hosted ObjectOS Cloud loads no code plugins. One hosted process serves many environments' kernels, so it is not a dedicated runtime (#27108 ruling item 4's rule, applied to hosted). Follows from decision 2 (no fetch or shelf path while M2/M4 are frozen); the thread's card on this question was closed as this option on that basis. | Code plugins are for self-hosted and Enterprise dedicated runtimes only (M1's local install). Hosted reaches vendor suites through bridges. |
| 4 | Where the code lives. Bridges: objectstack-ai/bridges (public, independent versions, no import of platform internals). Generic interfaces: objectstack-ai/objectstack. Our hosted bridge instances' deployment config: objectstack-ai/cloud, pinning a bridge release. |
— |
How a bridge meets the platform
| Need | Platform side (standard) | Bridge side |
|---|---|---|
| Actions (send a work notice, create a to-do, read the directory) | OpenAPI / MCP connector app — #27293, no new card | calls the vendor API, reshapes requests and replies |
| Per-person notifications (approval → the approver's DingTalk) | webhook messaging channel — outbox exists, per-recipient channel missing (B1) | delivers to the person's vendor account |
| Callbacks (a button pressed in a vendor card) | inbound webhook → flow — exists (flow api trigger) |
verifies and decrypts the vendor callback, forwards it |
| Sign-in (QR login, in-app silent login) | OIDC — exists both sides; hosted needs one upstream entry per bridge (B3) | wraps the vendor's OAuth / auth-code flow as an OIDC provider; no new "create a session from an external identity" API is needed |
| Directory and user mapping | SCIM provisioning into the environment — exists (cloud ADR-0071); gaps in B4 | reads the vendor directory; vendor user id → externalId (that IS the mapping; no mapping object) |
Children (each filed by the owning lane, Part of this epic)
- B1 — notification channel over the existing HTTP outbox (objectstack,
server, S). The delivery machinery exists:plugin-webhooks(sys_webhook, HMACX-Objectstack-Signature, durable outbox, retries, cluster dispatcher;packages/services/service-messaging/src/http-outbox.ts) already POSTs record events. What is missing is a per-recipient messaging channel:registerChannelProvideris called foremailandsmsonly (messaging-service-plugin.ts:458,:477), so a notification addressed to a person (recipient, preferences, template) cannot reach a URL. B1 = awebhookchannel provider that enqueues into the same outbox, carrying the recipient'sexternalId, the rendered content and the deep link. - B2 — inbound callbacks: no card, already exists. A flow's
apistart node arms a signed inbound hook (packages/spec/src/automation/api-trigger-secret-ref.zod.ts,flow.zod.ts:1117), and a wait node resumes on an incoming webhook (node-executor.zod.ts:31). The bridge verifies and decrypts the vendor callback, then posts to that hook. - B3 — "Sign in with " on the Cloud identity center (cloud, S). The mechanism exists on both sides: environments take an external OIDC/SAML IdP through
@better-auth/sso(bring-your-own IdP; Business+ on hosted), and the Cloud identity center already federates social logins — but as a fixed list of Google / GitHub / Microsoft from environment variables (packages/service-cloud/src/control-plane-preset.ts:444-450). B3 = one generic OIDC upstream entry (better-authgenericOAuth) per bridge, so every hosted environment gets the button. Self-hosted: documentation only. - B4 — SCIM for bridges: two gaps only (cloud + objectstack). SCIM itself is built: cloud ADR-0071 put
@better-auth/scim(SCIM 2.0/Users,active:false→ ban + session revoke) in each environment, and the hosted kernel mounts it by plan (planAllowsScim,packages/objectos-runtime/src/artifact-kernel-factory.ts:103,:315-355; EE turns it on with theFEATURE_SCIMlicence,apps/objectos-ee/objectstack.config.ts:763-769). A bridge is an external directory client, the same role as Okta, so ADR-0071 D2's "no cloud-as-SCIM-client" does not apply. What remains: (a) Users only, no/Groups(ADR-0071 D4): DingTalk departments →sys_business_unitand department → role are not covered — ADR-0071's out-of-scope line even names 钉钉 / 企业微信 / 飞书 org-structure sync; (b) tier: SCIM is Enterprise-only (clouddocs/design/pricing.md:127) — a maintainer decision (below) before a bridge relies on it for Team customers. - B5 — bridge-kit + bridge-dingtalk (bridges). Kit: OIDC provider shell, SCIM client, webhook relay, vendor callback crypto (the token cache landed in
80b4abd). DingTalk: actions (connector app's OpenAPI description), notifications (B1), sign-in (B3), directory (B4). Ships as our hosted instance and a Docker image. Acceptance carried over from ADR-0025 SDK contract — the three public seams external plugins build on (messaging channel provider, identity-object writes, PluginContext subset), a conformance testkit, the peer-dependency build check, and theobjectstack-ai/pluginsrepository #27287: an approval notification reaches a mapped DingTalk user with a deep link back to the record — plus sign-in with DingTalk and a directory sync. - B6 — compatibility (bridges + objectstack). A nightly contract test of each bridge against the platform's
nextbuild, and a conformance kit for the standard interfaces in objectstack. - WeCom and Feishu bridges are filed after DingTalk proves the kit.
Open maintainer decisions (decision cards when the child is dispatched)
- Who registers the vendor app: one ISV third-party app on the DingTalk open platform shared by all customers (better onboarding; needs ISV qualification and listing) vs each customer's own internal app with its key entered in the environment (works today).
- Tier: is "Sign in with DingTalk" a social login (every tier, like Google/Microsoft), and is directory sync over SCIM Enterprise-only as SCIM is today — which would leave Team customers in China without it?
Rules every child inherits
- ⛔ The platform never runs vendor code for this epic; a need that only in-process code can meet is a [Epic] ADR-0025 plugin package distribution — the next development phase: M0 record v2, M1 local T0 install loop (first-party, self-signed), M2 cloud fetch + per-plugin permission enforcement, M3 third-party sandbox tier #27108 question, not a bridge.
- ⛔ Bridges are stateless toward customers: credentials arrive per request from the environment's own credential store and are never stored or logged; only derived tokens are cached (bridges
AGENTS.md). - ⛔ Bridges import no
@objectstack/*internals; a missing standard interface is a platform card under this epic.
Done-when
- B1 and B3 landed (and B4 for the gaps it carries), in the cloud pin.
bridge-dingtalkreleased, hosted for ObjectOS Cloud and available as a Docker image; on a hosted environment a user signs in with DingTalk, the directory syncs, and an approval notification reaches the approver's DingTalk with a deep link.- The nightly contract test runs green against platform
next.
Related
#27108 (code plugins; ruling recorded there) · #27287 (frozen) · #27293 (connector apps; cloud#3353 E4 shelf lists each bridge's connector app) · #27230 (credential S1) · ADR-0024 (identity) · objectstack-ai/bridges docs/architecture.md.
Activity
objectstack-fleet commentedon Nov 8, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Ruling: #27314 · pause (
pm:on-hold) · maintainer 「集成桥接 #27314 暂停」 2026-11-08T16:26ZCheckpoint (the #31502 pause rule)
⛔ Not a claim.
Blocked-by:for order).Generated by Claude Code