Activepieces Enterprise Edition 架构解析:版本切换、特性门控与平台计划限量的实现指南

发布时间:2026/9/15 13:42:00
Activepieces Enterprise Edition 架构解析:版本切换、特性门控与平台计划限量的实现指南
Activepieces Enterprise Edition 架构解析版本切换、特性门控与平台计划限量的实现指南【免费下载链接】activepiecesAI Agents MCPs AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepiecesActivepieces 的企业版Enterprise EditionEE并非独立代码库而是在社区版CE之上叠加的一组商业特性模块全部位于packages/server/api/src/app/ee/目录下。本文从源码出发完整拆解 EE 的模块组织纪律、三种特性门控模式模块级 / 端点级 / Hooks 模式、PlatformPlan上的计划标志与限量语义以及新增一个 EE 特性的标准操作流程帮助开发者在理解架构的同时掌握扩展与排查的正确姿势。读完后你将能够定位任意 EE 模块的注册位置与门控钩子、读懂platformMustHaveFeatureEnabled的 402 拦截原理、理解 Hooks 工厂这一 CE/EE 接缝的设计意图并按照仓库约定安全地新增或修改企业特性。EE 与 CE 的边界代码组织与导入纪律EE 的代码全部生活在packages/server/api/src/app/ee/这一个目录树下每个企业特性一个子目录。这个组织方式背后有一条硬性纪律EE 代码绝不从 CE 反向被导入EE code is never imported from CE。反过来CE 通过声明“钩子接口”hook interface来预留扩展点EE 在版本切换时注入真实实现。这条纪律保证了社区版编译产物中不携带任何 EE 逻辑也让所有调用方caller保持“版本无关”edition-agnostic——它们只依赖 CE 声明的接口不关心当前运行的是 CE、EE 还是 Cloud。packages/server/api/src/app/ ├── app.ts # 版本切换edition switch ├── helper/ │ └── hooks-factory.ts # CE/EE 接缝hooksFactory.create / .set ├── platform/ │ └── billing-provider.ts # BillingProvider 契约 CE no-op 默认 └── ee/ # 全部 EE 模块一个目录一个模块 ├── authentication/ # 授权门控钩子、SAML、联邦、OTP、项目角色 RBAC ├── platform/platform-plan/ # PlatformPlan 实体、Autumn 计费 provider、license-key 激活 ├── audit-logs/ # 审计日志 ├── api-keys/ # API 密钥 ├── ...其余模块见下文全景表 └── helper/ # SMTP 邮件服务、外观/品牌定制关键文件EE 模块源码根目录 —— 所有 EE 模块每个模块一个目录版本切换入口 —— 按ApEdition条件注册 EE/Cloud 模块Hooks 工厂CE/EE 接缝 ——hooksFactory.create与.setEE 授权门控钩子 —— SAML、联邦、OTP、项目角色 RBACPlatformPlan 实体与计费 —— 计划标志与限量、Autumn 计费 provider、license-key 激活EE 辅助模块 —— SMTP 邮件服务与外观/品牌定制三种特性门控模式Feature Gating PatternsEE 特性在不同层级上被“打开/关闭”源码中形成了三种递进的门控模式1. 模块级门控版本切换注册在 app.ts 中system.getEdition()读取当前版本ApEdition.CLOUD/ApEdition.ENTERPRISE/ApEdition.COMMUNITY随后switch (edition)按版本条件注册模块switch (edition) { case ApEdition.CLOUD: await app.register(adminPlatformModule) await app.register(platformPlanModule) await app.register(appSumoModule) // ... billingProvider.set(autumnBillingProvider) // EE/Cloud 注入真实实现 break case ApEdition.ENTERPRISE: await app.register(platformPlanModule) // ... 企业版同样注册大部分 EE 模块但不含 Cloud-only 模块 billingProvider.set(autumnBillingProvider) break case ApEdition.COMMUNITY: await app.register(platformProjectModule) await app.register(communityPiecesModule) await app.register(otpModule) break }这是第一道闸模块本身只在对应版本下被注册。注意 Cloud 版本额外注册了adminPlatformModule、appSumoModule等Cloud-only模块详见“Gotchas”。2. 端点级门控platformMustHaveFeatureEnabled模块注册了并不代表所有端点对当前平台可用。每个被门控的 EE 模块会把自己注册为 Fastify 的preHandler钩子检查平台计划上的布尔标志app.addHook(preHandler, platformMustHaveFeatureEnabled((p) p.plan.myFlag))platformMustHaveFeatureEnabled的实现位于 ee-authorization.ts从请求主体principal中取出platformId调用platformService(...).getOneWithPlanOrThrow(platformId)拿到带计划的平台执行传入的谓词handler(platform)若返回false抛出ActivepiecesError错误码为FEATURE_DISABLED—— 该错误最终以HTTP 402返回给调用方。export const platformMustHaveFeatureEnabled (handler: (platform: PlatformWithoutSensitiveData) boolean): onRequestAsyncHookHandler async (request, _res) { const platformId platform in request.principal ? request.principal.platform.id : null if (isNil(platformId)) { throw new ActivepiecesError({ code: ErrorCode.AUTHORIZATION, params: { message: Platform ID is required } }) } const platform await platformService(request.log).getOneWithPlanOrThrow(platformId) const enabled handler(platform) if (!enabled) { throw new ActivepiecesError({ code: ErrorCode.FEATURE_DISABLED, params: { message: Feature is disabled } }) } }该函数从 ee/authentication/ee-authorization.ts 导出是绝大多数被门控 EE 模块的“标准门卫”。同文件还提供了platformMustBeOwnedByCurrentUser、platformToEditMustBeOwnedByCurrentUser、projectMustBeTeamType等平台/项目级授权助手供不同权限场景复用。3. Hooks 模式CE 声明 no-op 默认EE.set()真实实现对于需要“CE 有默认行为、EE 替换行为”的场景仓库用hooksFactory定义接缝。以 hooks-factory.ts 的实现为例export const hooksFactory { createT(defaultHooks: (log: FastifyBaseLogger) T) { let hooksCreator: (log: FastifyBaseLogger) T return { set(newHooksCreator: (log: FastifyBaseLogger) T): void { hooksCreator newHooksCreator }, get(log: FastifyBaseLogger): T { if (isNil(hooksCreator)) { return defaultHooks(log) } return hooksCreator(log) }, } }, }CE 侧调用hooksFactory.createT(ceDefault)创建一个接缝对象默认返回 no-op 实现EE/Cloud 侧在版本切换时调用.set(eeImpl)注入真实实现业务调用方统一通过.get(log)获取实现完全感知不到版本差异。这一模式被广泛使用projectHooks、flagHooks、publishHooksFactory、billingProvider、resumePageHooks、flowPublishHooks等均在 app.ts 中完成注入。一个具体实例计费接缝billingProvider。billing-provider.ts 中CE 默认 provider 是一个完整的 no-oplistPlans返回空数组、getCreditUsage返回{ total: 0, byProject: [] }、shouldBlockOnCredits返回false、isBillingEnforced返回false即失败开放。EE/Cloud 版本则在app.ts中通过billingProvider.set(autumnBillingProvider)注入基于 Autumn 的真实实现。该契约包含listPlans、getBillingOverview、createCheckoutSession、adjustUnconsumableFeatureQuantity座位数、configureAutoTopUp、trackFeature、ensureEnrolled、refreshEntitlements、activateLicense、isBillingEnforced、shouldBlockOnCredits、getCreditsAndAppSumoState、getConsumablesUsage、getCreditUsage等全部方法签名。值得注意的边界限量检查checkUsersExceededLimit、checkActiveFlowsExceededLimit并不在billingProvider契约上——它们是纯数据库投影读取不涉及 provider I/O由platformPlanService直接调用。EE 模块全景按功能域与计划标志原文档列出的 EE 模块可按功能域分组如下括号内为该模块对应的PlatformPlan布尔标志未标注 gate 的为不设门控的模块功能域模块计划标志plan.*治理与安全audit-logsauditLogEnabledapi-keysapiKeysEnabledsecret-managerssecretManagersEnabledscimscimEnabledoauth-apps、platform-webhooks、alerts随计划投影连接与集成管理global-connectionsglobalConnectionsEnabledpiecesplatform-piece piece-setmanagePiecesEnabledtemplatemanageTemplatesEnabled项目与团队projects / project-roleprojectRolesEnabled/customRolesEnabledproject-release git syncenvironmentsEnabledproject-members、project-plan不设门控ungated嵌入与认证signing-key managed-authn嵌入embeddingEnabledauthentication saml federatedssoEnabledotp、enterprise-local-authn、project-role RBAC随计划投影计费与授权platform-planAutumn 计费 license-key 激活——license-key-usage-report、appsumo、flagsenterpriseFlagsHooks——平台运营helperSMTP 外观、users、admin——一个值得注意的历史遗留custom-domains 模块已被移除但customDomainsEnabled列因向后兼容而保留在实体上。Cloud-only 与自托管 EE 的差异appsumoAppSumo 集成与cloud admin是Cloud-only模块自托管 EE 不注册它们见 app.ts 中ApEdition.CLOUD分支独有的appSumoModule、adminPlatformModule等。计划标志与限量PlatformPlan投影语义EE 特性的开关最终落在PlatformPlan实体上特性标志Feature flags布尔值列如ssoEnabled、scimEnabled、auditLogEnabled、embeddingEnabled、agentsEnabled等限量LimitsNullable(number)列语义为null 不限制unlimited、0 无none、N 上限cap。主要包括activeFlowsLimit—— 活跃流程数上限projectsLimit—— 项目数上限billedTeamProjectsLimit—— 计费团队项目数数值列旧的NONE/ONE/UNLIMITED字符串列teamProjectsLimit保留至清理 PR对应决策 000019usersLimit—— 用户席位上限scheduledUsersLimit—— 待执行的计划降级后的席位上限席位检查强制执行min(usersLimit, scheduledUsersLimit)。PlatformPlan是整个计费体系的投影缓存projection cache它是对平台在 Autumn 计费系统Autumn billing中客户订阅权益的本地镜像请求路径上的读取从不内联调用 Autumn。所有这一切最终都来自平台的 Autumn 权益投影深层计费细节见 EE Platform (Plans Billing)。从源码看限量检查platform-plan.service.ts 中getUsage从 AP 数据库统计活跃流程、团队项目与席位const activeFlowsCount await flowRepo().createQueryBuilder(flow) .innerJoin(project, project, project.id flow.projectId) .where(project.platformId :platformId, { platformId }) .andWhere(flow.status :status, { status: FlowStatus.ENABLED }) .andWhere(flow.operationStatus ! :deleting, { deleting: FlowOperationStatus.DELETING }) .getCount()而checkUsersExceededLimit则展示了**数据库权威DB-authoritative**的限量执行方式checkUsersExceededLimit: async ({ platformId, entityManager, additionalSeatsNeeded 1 }) { if (ApEdition.COMMUNITY edition) return if (additionalSeatsNeeded 0) return if (!await billingProvider.get(log).isBillingEnforced(platformId)) return const platformPlan await platformPlanRepo(entityManager) .createQueryBuilder(platform_plan) .setLock(pessimistic_write) // 事务内 FOR UPDATE防止并发超卖 .where(platform_plan.platformId :platformId, { platformId }) .getOne() if (isNil(platformPlan)) return const usersLimit effectiveUsersLimit(platformPlan) // min(usersLimit, scheduledUsersLimit) if (isNil(usersLimit)) return const { usedSeats } await countUsedSeats({ platformId, log, entityManager }) if (usedSeats additionalSeatsNeeded usersLimit) { throw new ActivepiecesError({ code: ErrorCode.QUOTA_EXCEEDED, params: { metric: PlatformUsageMetric.USERS } }) } }其中effectiveUsersLimit正是对min(usersLimit, scheduledUsersLimit)的实现决策 000017-scheduled-downgrades-cap-seats-immediately。席位统计usedSeats 活跃用户 未过期待处理邀请邀请占位决策 000014-pending-invitations-reserve-seats降低限量前还会通过assertSeatsNotBelowActiveUsers做“座位数不得低于活跃用户数”的数据库权威下限校验决策 000013-active-user-seat-floor-is-enforced-db-authoritatively。计划常量的两种形态packages/core/shared/src/lib/ee/billing/index.ts 定义了两种“字面量计划”AUTUMN_FREE_PLANCloud 免费计划plan: free、includedCredits: 100、projectsLimit: 1、usersLimit未显式给出为undefined即不限但showPoweredBy: true、ssoEnabled: false等OPEN_SOURCE_PLANCE/EE 的初始计划aiProvidersEnabled: true、chatEnabled: false、agentsEnabled: false、showPoweredBy: false、includedCredits: 0等。初始计划按版本区分CE/EE →OPEN_SOURCE_PLANCloud →AUTUMN_FREE_PLANCE 与TESTING环境完全跳过 enrollment/sync。Gotchas必须知道的关键注意事项原文档沉淀了多条踩坑经验是理解 EE 架构的“隐形文档”逐条继承如下部分模块是 Cloud-only自托管 EE 不包含AppSumo、cloud admin。判断一个模块是否能在自托管 EE 生效直接看 app.ts 的ApEdition.ENTERPRISE分支是否注册它。platform_plan是投影缓存手改标志不持久。懒加载的refreshEntitlements在任何计划读取时都会用 Autumn 数据重写计划列——手工改的 flag 只在下次同步前有效。真正干净的本地解锁方式是同时把autumnCustomerId与autumnApiKey两列置空loadAutumnCreds只有在两者都为空时才返回 nullrefreshEntitlements随即在update()之前返回手改的 flag 才能保持。只置空一个会命中最坏情况报error级Autumn credentials incomplete for an enrolled platform且所有计费调用静默 no-op。AP_EDITIONce时platform_plan行被完全忽略。platform.service.ts的getPlan在读取数据库之前就为 Community 返回OPEN_SOURCE_PLAN字面量行仍然存在因为createInitialBilling会写入它这让人误以为改 SQL 有效。在 CE 上本地解锁 flag 的正确方式是修改 packages/core/shared/src/lib/ee/billing/index.ts 中的字面量限量语义上null在两侧都表示不限而0表示“该计划不提供”且会额外隐藏该功能的 UI。注意编辑后需要同步修补/重建packages/core/shared/dist/——API 通过 node_modules 解析activepieces/shared的main: ./dist/src/index.js而 Web 应用通过 tsconfig 路径解析到src/只改src会造成前后端不一致的假象且src被版本跟踪提交前务必还原。运行本地计费意味着让本地后端指向 console而不是自建 Autumn。三个条件必须全部满足否则 provider 就是空 no-opAP_EDITION必须是cloud或eeAP_ENVIRONMENT不能是testingRedis 必须可用计费读写都走 Redis 缓存。AUTUMN_CONSOLE_URL默认指向生产 consolehttps://console.activepieces.com未配置的本地实例会以 owner email 注册一个真实客户——本地调试应把它指向测试 console。激活流程中的时序细节activateLicense中 console 调用发生在保存platform_plan.licenseKey之前——被拒绝的 key 永远不会被持久化。且首次聊天的计划授权chatPlanGrant.grant必须在信用门控运行之前完成await而非 fire-and-forget否则用户第一条消息会被QUOTA_EXCEEDED弹回重试才成功。AutumnFeatureId是三方契约每个值必须同时等于platform_plan列名投影通过mapAutumnFeaturesToPlatformPlan原样写入、AutumnfeatureId以及 Autumn 仪表盘中的功能 id。任何一侧改名都会悄悄破坏该功能的投影或计量。唯一的例外是teamProjectsLimit投影到plan.billedTeamProjectsLimit决策 000019。失败开放fail open是设计而非缺陷运行路径上的信用门控只会在计划携带billingEnforced标志且缓存余额耗尽时才阻塞未知余额冷缓存或 Autumn 不可达出错时返回null在任何一层都不会阻塞决策 000020-credit-gating-fails-open-on-an-unknown-balance。AppSumo 积分耗尽时则无论billingEnforced如何都阻塞。AP_EDITIONee时shouldBlockRunOnCredits直接返回false自托管 EE 在运行准入上做零计费 I/O——这是延迟权宜之计而非策略。新增platform_plan属性会强制构建失败直到你说明它的值从哪来。mapAutumnFeaturesToPlatformPlan返回PlatformPlanProjectionRequiredPick...每个属性要么被投影要么在NotProjectedFromAutumn名单中明确豁免licenseKey、licenseExpiresAt、projectsLimit、dedicatedWorkers、canary、customDomainsEnabled、workerGroupId。新增FeatureFlagId且同时有列时还必须在toPlatformPlanFlags中映射。这些构建错误只有在activepieces/shared重建后才会出现tsc -p packages/server/api/tsconfig.app.json的paths: {}解析到 distvitest 则相反别名到 src立即看到 schema 变更。独立ee/license-keys/模块已删除。旧的远程验证、试用追踪器、flag 映射逻辑全部随计费迁移到 Autumn 而移除——license key 现在只是平台 Autumn 客户的激活/恢复句柄由 platform-plan 计费 provider 处理。详见 License Keys。新增一个 EE 特性的标准流程原文档给出了一条经过验证的“新增 EE 特性”清单完整继承如下创建模块在packages/server/api/src/app/ee/下新建目录实现该特性的全部路由与服务添加计划标志在PlatformPlan实体上新增布尔列特性标志或限量列同时完成两处映射——Autumn 功能映射在autumn-utils.ts的mapAutumnFeaturesToPlatformPlan中登记计划常量同步更新OPEN_SOURCE_PLAN/AUTUMN_FREE_PLAN位于 packages/core/shared/src/lib/ee/billing/index.ts端点门控用platformMustHaveFeatureEnabled((p) p.plan.myFlag)注册preHandler钩子注册模块在 app.ts 的ApEdition.CLOUD与ApEdition.ENTERPRISE分支中app.register(...)Cloud-only 特性只注册前者如需扩展 CE 行为在 CE 中定义 hook 接口hooksFactory.createT(ceDefault)在 EE 中通过.set(eeImpl)注入真实实现。这套流程与三种门控模式一一对应是理解 EE 架构后最直接的产出物。总结与延伸阅读EE 架构的核心可以概括为三句话代码按目录隔离ee/能力按版本注册edition switch开关按计划投影PlatformPlan Hooks 接缝。三条纪律共同保证了 CE 始终是可独立运行的完整产品而 EE 只是以“接口注入”方式叠加的商业能力层。想深入计费与权益投影机制继续阅读EE Platform (Plans Billing) —— Autumn 计费、信用计量与门控、席位管理的完整细节License Keys —— license key 作为 Autumn 客户激活句柄的机制决策文档000013、000014、000017、000019、000020核心入口文件速查关注点文件EE 模块门控钩子入口ee/authentication/ee-authorization.ts版本切换与模块注册app.tsCE/EE 接缝helper/hooks-factory.ts计费契约与 CE no-opplatform/billing-provider.ts计划投影、用量与座位检查ee/platform/platform-plan/platform-plan.service.ts计划常量与 schemacore/shared/src/lib/ee/billing/index.ts【免费下载链接】activepiecesAI Agents MCPs AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考