Documentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
Cross-Core Integration, Events, Automator & Workflow — Deep Dive & Recommendations
Version: 1.0
Last Updated: 2026-03-11
Status: Analysis and recommendations
This document provides a deep dive into cross-core integration strategy, event consumer/pub-sub, the automation engine, and workflow execution — with identified gaps and a consistent approach for improvement.
1. Cross-Core Integration Strategy
1.1 Current State
The platform uses three integration patterns (constitution §1.3, PLATFORM_INTEGRATION_LAYERS.md, CROSS_CORE_INTEGRATIONS.md):
| Pattern | Use Case | Implementation |
|---|
| 1. Platform Integration Layer | Shared capability used by multiple cores | @/platform/* (forms, notifications, workforce, workflow canvas, realtime, events, etc.) |
| 2. Event-Based Integration | Loose coupling, async, audit trail | Domain events via publishEvent() → fw_domain_events; HTTP event-consumer; DB triggers → pg_notify (documented channels) |
| 3. API Contracts | Synchronous request-response | Documented in API_CONTRACTS.md; many planned, few implemented as formal REST |
Strengths:
- Clear decision tree in
.cursor/rules/integration-patterns.md and constitution.
- Platform layers are well-documented (Forms, Notifications, Workforce, Realtime, Events).
- Event channels and naming are defined in EVENT_CONTRACTS.md with canonical channels (
domain_events, automation_trigger, fa_events, cl_pm_events, etc.).
- Cross-core FK is scoped (ADR-002: CL may reference
pm_encounters.id only).
- Dependency graph in CROSS_CORE_INTEGRATIONS.md is up to date.
1.2 Gaps & Inconsistencies
| Gap | Description |
|---|
| Event delivery vs documentation | EVENT_CONTRACTS and DATA_FLOW describe pg_notify → “Edge Function Listener.” Edge functions are HTTP-invoked; there is no in-repo pg_notify → HTTP bridge (e.g. Supabase Database Webhooks or a worker). So “listener” is either external or unimplemented. |
| Dual event paths | Two distinct mechanisms: (A) Table-driven: publishEvent() → fw_domain_events → trigger fw_process_domain_event() → inserts fw_workflow_executions (queued). (B) HTTP-driven: Client or service invokes event-consumer with event_type + payload. They are not unified; which to use when is not always obvious. |
| API contracts | API_CONTRACTS lists many planned contracts (e.g. FA → RH episode balance, HR → RH employee lookup). Implementation status is mixed; no single “contract registry” with implementation status and version. |
| Platform layer index | PLATFORM_INTEGRATION_LAYERS has a good table; some entries are “Planned” or “In Progress.” A single “integration health” view (events, API, platform layers) would help. |
2. Event Consumer & Pub/Sub
2.1 Current Mechanisms
Path A — Domain events table (FW automation / workflow):
- Cores call
publishEvent({ event_name, organization_id, payload }) from @/platform/events.
- Event is inserted into
fw_domain_events.
- DB trigger
fw_process_domain_event() runs on INSERT:
- Matches
fw_automation_rules with trigger_type = 'event' (or pm_event) and event_config/trigger_config.
- For each match, inserts a row into
fw_workflow_executions with status = 'queued' and trigger_payload.
Path B — HTTP event-consumer:
- Caller (client or edge function) invokes
supabase.functions.invoke('event-consumer', { body: { event_type, payload } }).
event-consumer edge function:
- Validates auth and body.
- Runs Teams notifications (if
pf_teams_notification_config has a rule for event_type).
- Runs domain handlers (e.g.
referral_accepted → CL transition + discharge checklist; other event types can be added in code).
- No subscription to PostgreSQL NOTIFY; invocation is push-by-caller only.
Path C — Realtime (Supabase):
- Postgres Changes: Client subscribes to table changes (e.g.
fw_workflow_executions, pf_notifications) via @/platform/realtime hooks. Used for live UI updates, not for “event routing” to server-side handlers.
- Broadcast: Ephemeral, non-persisted; used for typing, presence, or in-app signals. Not used as the primary event bus for cross-core domain events.
Path D — pg_notify (documented, server-side consumer unclear):
- EVENT_CONTRACTS and DATA_FLOW describe channels (
domain_events, automation_trigger, fa_events, etc.) and say “Subscribers consume via edge functions that listen to pg_notify.”
- In the repo there is no edge function that “listens” to pg_notify (edge functions are HTTP-triggered). So either:
- A Supabase Database Webhook (or similar) maps NOTIFY to HTTP and calls an edge function, or
- The intended “listener” was never implemented and form/DB-triggered flows rely on something else (e.g. client invoking automation-executor after form submit).
2.2 Gaps
| Gap | Description |
|---|
| No single “event bus” doc | Table-driven (fw_domain_events) vs HTTP (event-consumer) vs pg_notify are described in different places. One “Event delivery options” section with “when to use which” would reduce confusion. |
| event-consumer handler registry | Handlers are hardcoded in event-consumer/index.ts. Adding a new event type requires code change and deploy. A small registry (e.g. event_type → handler name or config) could make it easier to extend. |
| Queued workflow executions | fw_process_domain_event() queues executions; no in-repo worker or cron that picks status = 'queued' and runs them (e.g. by calling automation-executor or a dedicated execution runner). So event-triggered rules may never run unless something else processes the queue. |
| Form submission → automation | DATA_FLOW describes: form INSERT → trigger → pg_notify(‘automation_trigger’) → automation-executor. No migration defines trigger_automation_on_submission; automation-executor is invoked only via HTTP (e.g. dry-run). So either form-triggered automation is implemented elsewhere (e.g. client or webhook) or it is a gap. |
3. Automator (FW-03)
3.1 Current State
- Rules:
fw_automation_rules with trigger_type, trigger_config, event_config, date_relative_config, conditions, status. Actions in fw_automation_actions.
- Trigger types:
form_submitted, form_updated, field_changed, schedule, webhook, manual, pm_event, event, date_relative.
- Executor: Edge function
automation-executor:
- Invoked via HTTP with body
{ trigger_data, dry_run? }.
- Validates JWT and org access (V2 pattern with
pf_user_role_assignments).
- For form triggers, expects
trigger_data with trigger_type, submission_id, form_id, organization_id, submission_data, etc.
- Fetches matching rules, evaluates conditions, executes actions (send_email, send_notification, update_record, create_record, call_webhook, run_function), supports visual workflow graph (FW-06 Phase 2) and variables (FW-18).
- Event-triggered rules: When an event is inserted into
fw_domain_events, fw_process_domain_event() only queues executions (inserts into fw_workflow_executions). The automation-executor is not invoked for those queued rows in the codebase (no cron or worker that reads fw_workflow_executions and calls the executor).
3.2 Gaps & Inconsistencies
| Gap | Description |
|---|
| Trigger config shape | Different trigger types use different columns: event_config, date_relative_config, trigger_config (for pm_event, form_submitted). Documented in FW AGENTS.md; edge function and UI must handle all consistently. |
| Who invokes executor for form submit? | If there is no DB trigger → pg_net → automation-executor, then either the client must call automation-executor after form submit (with trigger_data), or a separate mechanism (e.g. cron polling fw_form_submissions) must exist. Not clearly documented. |
| Queued executions not processed | Event and pm_event triggers only create fw_workflow_executions with status queued. A workflow execution processor (cron or DB-triggered HTTP) that picks queued rows and runs them (via automation-executor or an internal runner) is missing or lives outside this repo. |
| PM-19 vs event registry | PM-19 uses trigger_config with PMEventTriggerConfig; these events are not in fw_workflow_events. Documented as intentional; keep a single place that lists “event-triggered” vs “PM-internal” so automation UX stays consistent. |
4. Workflow
4.1 Current State
- Visual workflow (FW-06): Workflow builder (React Flow), definitions stored in DB; execution is driven by automation-executor when invoked with appropriate trigger_data (e.g. form_submitted or workflow_execution payload). Executions stored in
fw_workflow_executions; realtime subscription used for monitoring.
- XState machine (FW-18):
createWorkflowMachine / useWorkflowMachine in @/cores/fw/machines — client-side step machine (form, approval, action, condition, notification, wait). Not wired to the server-side workflow definition or automation-executor; no production callers outside the machines module. FW AGENTS.md and FORMS_WIZARDS_WORKFLOWS_AUTOMATIONS_RECOMMENDATIONS.md mark it as experimental / reserved for future use.
- Workflow vs automation: Workflow builder = graph of nodes (trigger, actions, conditions, approvals). Automation rules = single trigger + conditions + actions. Overlap in concept; different UX and data model.
4.2 Gaps
| Gap | Description |
|---|
| Two execution models | Server-side: definition → automation-executor → fw_workflow_executions. Client-side: XState step machine. They are not connected; avoid spreading a second execution model until there is a concrete product need (e.g. approval chain UI). |
| Single “Create automation” entry | Recommendation in FORMS_WIZARDS_WORKFLOWS_AUTOMATIONS_RECOMMENDATIONS: one entry point (“Simple rule” vs “Workflow”) to reduce confusion. |
| Platform workflow = visualization only | @/platform/workflow (WorkflowCanvas, swim lane) is for visualization only; execution stays in FW. Document this so new features don’t add execution logic to platform. |
5. Recommendations — Improvement, Gaps, Consistency
5.1 Cross-Core Integration
| Rec | Priority | Action |
|---|
| R1 | High | Unify event delivery documentation. Add a single “Event delivery” section (e.g. in EVENT_CONTRACTS or a new docs/architecture/EVENT_DELIVERY.md) that describes: (1) Table-driven: publishEvent() → fw_domain_events → trigger → queued workflow executions — use for FW automation/workflow triggers. (2) HTTP event-consumer: invoke('event-consumer', { event_type, payload }) — use for cross-core side effects (Teams, CL transitions, etc.) that need a single place to add handlers. (3) Realtime: Postgres Changes / Broadcast for UI only, not for server-side event routing. (4) pg_notify: Document current state: channels and DB triggers exist; server-side “listener” is either via Supabase webhooks/external worker or not yet implemented; clarify and document. |
| R2 | Medium | Integration health view. Add a short “Integration status” page or table: Platform layers (with status), API contracts (planned vs implemented), event channels (table vs HTTP vs pg_notify). Link from CROSS_CORE_INTEGRATIONS and PLATFORM_INTEGRATION_LAYERS. |
| R3 | Low | API contract registry. In API_CONTRACTS or a companion file, add a table: contract name, provider, consumer, status (planned / in progress / implemented), version. Keeps API strategy and implementation status in one place. |
5.2 Event Consumer & Pub/Sub
| Rec | Priority | Action |
|---|
| R4 | High | Implement or document queued execution processing. Either: (A) Add a cron-driven edge function (or worker) that polls fw_workflow_executions for status = 'queued', then invokes automation-executor (or a dedicated “run-workflow-execution” function) with the execution id and trigger_payload; or (B) Use Supabase Database Webhooks to call an edge function on INSERT to fw_workflow_executions where status = ‘queued’. Document the chosen approach in EVENT_CONTRACTS and in automation-executor README. |
| R5 | High | Form submission → automation. Confirm intended flow: (1) Client invokes automation-executor after form submit with trigger_data, or (2) DB trigger on fw_form_submissions + pg_net (or webhook) to call automation-executor. If (2), add the trigger and webhook; if (1), document it in FW-03 and DATA_FLOW so implementers don’t assume a DB listener. |
| R6 | Medium | event-consumer handler registry. Option A: Keep code-registered handlers but list them in a small table in EVENT_CONTRACTS (event_type → handler name, one-line description). Option B: Add a DB or config table (event_type → handler key) so new event types can be wired without code change. Prefer A for simplicity unless you need non-deploy configuration. |
| R7 | Medium | Idempotency and retries. For event-consumer and any new execution processor, document idempotency (e.g. event_id or execution_id idempotency key) and retry/backoff so handlers are safe when invoked more than once. Rationale: Prevents duplicate side effects and data corruption when events are retried or delivered multiple times. |
5.3 Automator
| Rec | Priority | Action |
|---|
| R8 | High | Trigger config reference in one place. Keep and maintain the “Automation trigger config reference” (trigger_type → config location and shape) in FW AGENTS.md; ensure automation-executor and UI both reference it and handle all trigger types. Add a short “Trigger config” section in EVENT_CONTRACTS or FW-03 spec for event/date_relative/pm_event. |
| R9 | Medium | Single “Create automation” entry. From the Automations dashboard, offer “Simple rule” (AutomationRuleBuilder) and “Workflow” (visual builder). Reduces confusion between rules and workflows (already recommended in FORMS_WIZARDS_WORKFLOWS_AUTOMATIONS_RECOMMENDATIONS). |
| R10 | Low | PM-19 and fw_workflow_events. Explicitly document that PM-19 event types are “PM internal” and not registered in fw_workflow_events; list them in a small table so event-driven automation behavior is predictable. |
5.4 Workflow
| Rec | Priority | Action |
|---|
| R11 | Medium | XState role. Keep XState workflow machine as “experimental / reserved for future” unless a concrete feature (e.g. approval chain UI, submission wizard) adopts it. Document in FW AGENTS.md and form-libraries-advanced-extensions: “Do not use in new features without a product requirement.” Avoid a second, parallel execution model. |
| R12 | Low | Workflow vs automation in docs. In FW AGENTS.md or a short “Workflow and automation” doc, state: “Visual workflows = multi-step automation with graph/approvals; Automation rules = single trigger → one or more actions. Use workflows for branching/approvals; use rules for simple when-X-then-Y.” |
| R13 | Low | Platform workflow = visualization only. In PLATFORM_INTEGRATION_LAYERS and platform workflow README, state that WorkflowCanvas / swim lane are for visualization only; execution lives in FW (automation-executor, fw_workflow_executions). |
5.5 Consistency Approach (Summary)
- One event narrative: Document the two main paths (table-driven for FW automation, HTTP event-consumer for cross-core handlers) and when to use each; clarify pg_notify and Realtime roles.
- Close the execution loop: Ensure “queued” workflow executions are processed (cron or webhook) and form submission triggers automation in a documented, consistent way.
- Single reference for triggers: One maintained “trigger config” and “event vs PM-internal” reference for automation and workflow.
- Unified automation UX: One entry point for creating automations (simple rule vs workflow) and clear guidance on workflow vs rule.
- No duplicate execution model: Keep XState experimental until a concrete feature uses it; execution remains server-side (automation-executor + fw_workflow_executions).
6. References