The shared Automations platform is the runtime and storage layer for event-driven workflows in BricksMembers. It owns workflow definitions, action definitions, queue orchestration, provider connections, provider adapters, and the migration of older BRM email automations into the shared model.
Primary Boundaries
- Automation core owns workflow persistence, runtime orchestration, queueing, and connection management
- Module trigger/action packs expose triggers and actions only when their modules are active
- Provider adapters own external HTTP calls, same-site provider boundaries, and provider-specific payload rules
- Emails module remains the owner of template rendering and email transport
- LevelAutomationRuleService remains separate and is not part of the shared workflow engine
Core Services
- AutomationSchemaService — owns shared automation table creation and verification
- AutomationWorkflowService — canonical workflow and action persistence owner
- AutomationQueueService — shared workflow queue ownership, claiming, retries, stale-claim release, and totals
- AutomationRuntimeService — event matching, enqueue rules, and claimed-job execution
- AutomationConnectionService — provider connection CRUD, verification, masking, target refresh, and the canonical connection write path for provider credentials
- AutomationSecretService — encrypted credential serialization/deserialization
- AutomationTriggerRegistryService — curated trigger catalog and trigger lookup
- AutomationActionRegistryService — action definition catalog
- AutomationConditionEvaluator — workflow condition matching
- AutomationWpActionPresetService and AutomationWpActionPresetCatalogService — curated WordPress, plugin, and BRM action preset definitions, builder filter schemas, and normalized preset trigger config
- AutomationBuilderOptionReadService — read-only owner for builder option payloads such as roles, users, posts, taxonomies, products, forms, tags, lists, groups, and offers
- AutomationContextResolver — normalized runtime context builder
- AutomationJobLogService — redacted provider/job log persistence
- AutomationHttpClient — shared outbound HTTP wrapper with HTTPS and redaction safeguards
- MailerPressLocalDataService — same-site MailerPress v2 runtime boundary for availability checks, target reads, contact lookup, contact upsert, and list/tag relation mutation since v1.1.0
- EmailAutomationMigrationService — imports legacy BRM email automations into the shared workflow store and enables cutover
- EmailAutomationCleanupService — post-cutover verification and optional legacy table cleanup
Shared Tables
brm_automation_workflowsbrm_automation_actionsbrm_automation_jobsbrm_automation_connectionsbrm_automation_job_logs
These tables are separate from the Emails transport queue. Email job delivery still uses brm_email_jobs.
The automation schema version is 4 for the query-performance queue indexes. brm_automation_jobs includes composite indexes for available-job claims, stale-heartbeat release, and failed-job retry scans. AutomationQueueService::release_stale_claims() intentionally runs separate updates for heartbeat_at IS NULL and heartbeat_at < cutoff so each path can use the queue indexes efficiently.
Action-Step Storage Contract
The canonical workflow-step contract now lives on brm_automation_actions. Each action row stores the action identity, order, timing, conditions, and provider-specific config for exactly one upcoming step.
action_orderremains the canonical persisted ordertiming_modeandtiming_config_jsonnow belong to the action row and define any delay before that action runsconditions_jsonnow belongs to the action row and defines any gating checks that must pass before that action runsaction_config_jsonremains the canonical provider-specific payload/config store behind the guided admin UI
The older workflow-level timing_mode, timing_config_json, and conditions_json fields remain compatibility summaries only. They are no longer the canonical source for multi-step delays or step-level gating.
Trigger and Action Registration
The trigger and action catalogs are intentionally modular. Core loads the registry services, but modules register their own trigger or action packs only when active.
EmailAutomationActionPackPaymentsAutomationTriggerPackProgressAutomationTriggerPackDripAutomationTriggerPackEnrollmentAutomationTriggerPackGroupAutomationTriggerPackSubmissionAutomationTriggerPackQuizAutomationTriggerPackCertificateAutomationTriggerPack
Since 0.9.94, WordPress action workflows also have a smart preset layer. The preset catalog covers common WordPress user/content/taxonomy/comment events, WooCommerce order events, FluentCRM tag/list events, Bricks form actions, and thin BRM event aliases. Since v1.1.0, the same smart preset layer also includes MailerPress contact, subscription, list, tag, and custom-field events. Preset runtime registration is gated by the required module and third-party plugin, so unavailable integrations do not register inactive hook listeners.
Smart preset event resolvers normalize hook arguments into structured context and subject references. AutomationRuntimeService uses those subject references for workflow dispatch identity and duplicate protection instead of relying only on a generic user ID or raw hook payload.
Native Analytics Relationship
Native analytics now reuses the semantic trigger catalog and automation context vocabulary, but it does not run through workflow storage, automation connections, or the automation jobs queue.
- Shared with analytics: semantic trigger aliases from
AutomationTriggerRegistryServiceand normalized event context - Not shared with analytics: workflow matching, queue orchestration, provider connection CRUD, and workflow action execution
This boundary matters because analytics is measurement, not automation. Do not route analytics events through AutomationRuntimeService or automation jobs just because both systems now speak the same event language.
Provider Adapters
Provider integration stays behind provider adapters under src/Integrations/Automations/. Remote providers use HTTP clients there, while same-site providers can use an explicit local data boundary. That keeps the admin layer and module packs free of transport and provider mutation logic.
MailchimpProviderAdapterBrevoProviderAdapterfor connection verification, list refresh, and contact-sync support behind the Brevo connectionMailerLiteProviderAdapterKitProviderAdapterMailerPressProviderAdapterwithMailerPressLocalDataServicefor same-site MailerPress v2 installs since v1.1.0OutboundWebhookProviderAdapter
Current Provider Action Families
The shared workflow catalog now includes first-party provider actions for the currently supported automation connections. These action definitions are registered centrally and then configured from the Builder tab after a compatible connection has been saved.
Brevo is intentionally different from the workflow-action providers below. It is configured on Automations → Connections as a membership contact sync with free-list selection and BricksMembers level-to-list mappings that use select fields plus selected-list pills; it does not register a Builder action family.
mailchimp_upsert_membermailchimp_update_member_tagsmailerlite_upsert_subscribermailerlite_add_groupsmailerlite_remove_groupsmailerpress_upsert_contactmailerpress_add_tagsmailerpress_remove_tagsmailerpress_add_listsmailerpress_remove_listskit_upsert_subscriberkit_add_tagskit_remove_tagsoutbound_webhook_send
Admin Surface
AutomationsPage— canonical route shell for Workflows, Connections, Builder, Jobs, and the conditional Upgrade Status tab
Admin pages validate and delegate only. They do not own workflow writes, queue writes, provider writes, or HTTP transport.
AutomationConnectionActions is the AJAX boundary for connection writes. Brevo-specific admin settings are saved through the same connection request and delegated into EmailBrevoSettingsService, so the Emails page does not expose a separate Brevo setup or second mutation path.
The visible tabs on the canonical route are Workflows, Connections, Builder, and Jobs. The Upgrade Status tab is conditional and only appears when a workflow upgrade or migration needs attention; its email item is titled Email Automation Upgrade. Healthy installs do not keep a permanent migration tab visible.
The Builder tab is now a visual flow editor. Trigger, timing, condition, and action steps are rendered as node cards in the admin adapter layer, but the save payload still posts directly into AutomationWorkflowActions and AutomationWorkflowService without creating a second storage path.
Normal action setup is also guided from the builder sidebar. The UI exposes fetched provider targets, context-path selectors, and field-mapping controls instead of asking the operator to write raw action JSON for routine cases. The underlying canonical persisted config remains action_config_json.
For native BRM email actions, the builder stores the selected Email Type as email_type on that action config. Values normalize to transactional or marketing. Marketing email actions consult the Emails module unsubscribe store and expose {{unsubscribe_url}} to the template; transactional actions are intended for account-critical messages and do not use marketing opt-out state.
That same simplification now applies to step conditions and trigger setup. In the normal builder UI, conditions are authored as guided path/operator/value rows on the upcoming action step, with operators such as equals, not_equals, in, not_in, contains_any, contains_all, contains_none, exists, and not_exists. Legacy trigger-match compatibility fields remain hidden compatibility data instead of a parallel user-facing setup path.
Sidebar help in the visual builder uses the shared BRM tooltip runtime. Dynamic builder panels emit standard help-text nodes and then rebind them into compact eye-icon tooltips after each sidebar render, so the admin adapter stays consistent with the shared help system instead of inventing a second tooltip implementation.
Security Rules
- all admin and AJAX entry points require the relevant BRM capability, normally
brm_manage_automations, plus nonce validation - provider credentials are encrypted before persistence
- shared logs store only redacted payloads and responses
- the shared HTTP client rejects unsafe URLs and enforces HTTPS outside development
- provider-specific secrets never appear in localized admin JS or log views
- MailerPress v1.1.0 integration is local-only: BRM stores no MailerPress API key, performs no same-site REST loopback, validates list/tag IDs before mutation, and logs only redacted counts plus an email hash
Migration Contract
Older email automations are migrated from the legacy email automation store into the shared workflow tables. The migration is resumable and idempotent. Cutover only happens after verification succeeds, and cleanup is handled separately.
During and after migration, the Emails module still owns templates and transport. Only the storage and runtime orchestration for event-based email automations moves into the shared platform.
Extension Points
brm_register_automation_triggersbrm_register_automation_actionsbrm_automation_contextbrm_automation_webhook_payload