> ## 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.

# Event Contracts

> Version: 2.2.2 Last Updated: 2026-05-18 Change Note: Added six BHRF (A.A.C. R9-10-701..722) event contracts (CL-68/GR-27/PM-74) with coded hold_reason and R7 idempotency.

**Version:** 2.2.2\
**Last Updated:** 2026-05-18\
**Change Note:** Added six BHRF (A.A.C. R9-10-701..722) lifecycle event contracts for CL-68 / GR-27 / PM-74 (`rh_resident_admitted` BHRF-filtered, `cl_bhrf_loc_determined`, `cl_bhrf_clinical_assessment_completed`, `pm_bhrf_continued_stay_review_required`, `gr_bhrf_compliance_finding_raised`, `pm_residential_charge_held`) with R7 retry alignment and coded (non-free-text) `hold_reason`. Prior: added explicit "no events" entry for CL-31; `cl_referral_status_updated` (CL-12-EN-67) on `cl_events`.
**Constitution Reference:** Section 1.3 (Integration Patterns - Pattern 2)

Event-based integration enables loose coupling between cores via domain events. Events are published using PostgreSQL `pg_notify` and consumed via database triggers or edge functions.

***

## Event Schema Standard

All events MUST follow this structure:

```typescript theme={null}
interface DomainEvent {
  event: string;              // Event name (e.g., 'rh_resident_admitted')
  publisher: string;           // Core that publishes (e.g., 'RH')
  subscriber: string[];        // Cores that subscribe (e.g., ['FA', 'HR'])
  payload: Record<string, any>; // Event-specific data
  metadata: {
    organization_id: uuid;
    site_id?: uuid;
    user_id: uuid;
    timestamp: timestamp;
    correlation_id?: uuid;
  };
}
```

***

## RH lifecycle events: canonical names & persistence (FW-16)

**Canonical names** match `KnownEventName` in `src/platform/events/types.ts` and rows in `fw_workflow_events` / inserts into `fw_domain_events`:

| Legacy / doc alias (deprecated)                 | Canonical `event_name`                                      | `fw_domain_events.event_source` (trigger)  | Source table / condition                                                             |
| ----------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------ |
| `resident_admitted`                             | `rh_resident_admitted`                                      | `trigger_rh_episodes_domain_events`        | `rh_episodes` — `status` transitions **to** `admitted`                               |
| `resident_discharged`                           | `rh_resident_discharged`                                    | `trigger_rh_episodes_domain_events`        | `rh_episodes` — `status` transitions **to** `discharged`                             |
| `phase_progressed` / `rh_phase_changed` (draft) | `rh_phase_advanced`                                         | `trigger_rh_episode_phases_phase_advanced` | `rh_episode_phases` — row becomes current phase                                      |
| `bed_assigned` (planned registry)               | `rh_bed_assigned` ✅ (now in `KnownEventName`)               | *Planned*                                  | Bed assignment mutation — add when HR consumer is scheduled                          |
| `bed_released` (planned registry)               | `rh_bed_released` ✅ (now in `KnownEventName`)               | *Planned*                                  | Bed release mutation                                                                 |
| `invoice_creation_requested`                    | `rh_invoice_creation_requested` ✅ (now in `KnownEventName`) | *Planned*                                  | Invoice creation request — align with FA consumer story to avoid duplicate invoicing |

**Realtime:** Consumers should read **`fw_domain_events`** (and FW-16 automation) as the source of truth. A dedicated `pg_notify` channel (e.g. `rh_events`) is optional and must not diverge from persisted domain events.

***

## Status Legend

* ✅ **Implemented** - Fully implemented and tested
* 📝 **Planned** - Specified but not yet implemented
* 🟡 **In Progress** - Partially implemented

***

## Canonical Event Channels

Use these channels when documenting or implementing events. New events must use the channel for their owning core. Reference this table from `specs/_templates/INTEGRATION_CONTRACT_TEMPLATE.md` when defining event contracts.

| Channel              | Owning Core(s) | Purpose                                                                                  |
| -------------------- | -------------- | ---------------------------------------------------------------------------------------- |
| `domain_events`      | PF / general   | General lifecycle events, HR-style events when no dedicated channel                      |
| `automation_trigger` | FW             | Form submission/update events (FW-03)                                                    |
| `fw_events`          | FW             | Forms & workflow events (external form submitted, approval submitted/completed)          |
| `fa_events`          | FA             | Finance events (journal posting, payments, budgets, consolidations)                      |
| `hr_events`          | HR             | HR lifecycle (credentials, onboarding, offboarding, performance)                         |
| `it_events`          | IT             | IT asset, license, ticket, vendor, procurement events                                    |
| `lo_events`          | LO             | Leadership (rocks, todos, meetings, issues)                                              |
| `cl_pm_events`       | CL, PM         | CL/PM cross-core (break-glass, eligibility, check-in, lab orders)                        |
| `cl_events`          | CL             | CL clinical events (note finalized, assessment, group session)                           |
| `pm_events`          | PM             | PM practice management (eligibility, appointments, claims)                               |
| `pm_rpa_events`      | PM             | PM-51 RPA automation events (execution completed, consecutive failures)                  |
| `rh_events`          | RH             | Recovery housing events (resident admission, discharge, census, episodes)                |
| `gr_events`          | GR             | Governance (incidents, audits)                                                           |
| `org_data_changes`   | PF             | PF-18 org data sync events (department/site changes triggering cross-module propagation) |

**Event naming:** For **new** events, use the canonical format `{core}_{entity}_{action}` (e.g. `hr_employee_hired`, `cl_assessment_completed`). Existing events may use the legacy dotted pattern (e.g. `hr.benefit_enrollment.created`).

**PM-51 RPA naming exception:** The PM-51 RPA events (`pm.rpa.execution_completed`, `pm.rpa.consecutive_failures`) use dotted naming as approved for this feature. This is an explicit exception to the standard underscore convention for backward compatibility with the RPA automation system. New PM events outside of PM-51 should follow the standard `pm_{entity}_{action}` format.

See INTEGRATION\_CONTRACT\_TEMPLATE.md § Event Naming Conventions.

***

## Event Delivery Mechanism

**Canonical guide:** [EVENT\_DELIVERY.md](./EVENT_DELIVERY.md) — how to choose table-driven vs HTTP consumer vs realtime vs external webhooks.

**Current Implementation (✅ Complete):**

* Events published via PostgreSQL `pg_notify` to dedicated channels:
  * `domain_events` - HR lifecycle events (credentials, onboarding, offboarding)
  * `automation_trigger` - FW form submission/update events
  * `fa_events` - FA financial events (journal posting, payments, budgets, consolidations)
  * `it_events` - IT module events (ticket created, contract/license expiring, asset assigned, purchase request submitted/approved)
  * `lo_events` - LO leadership events (rocks, todos, meetings, issues)
  * `cl_pm_events` - Active channel for CL/PM cross-core events (CL-01 break-glass, PM eligibility, appointment check-in to CL-04, CL-09 lab orders/results) — ✅ Active for CL-01, PM, and CL-09 integration events
  * `cl_events` - CL clinical events (note finalized, assessment completed, group session completed) — 📝 Reserved for CL-02+ internal events; not yet in use
  * `pm_events` - PM practice management events (eligibility verified) — 📝 Planned; channel reserved for PM-02+
* Subscribers consume via edge functions that listen to pg\_notify
* Events include full organization context for multi-tenant isolation
* All events logged to `pf_audit_logs` for permanent audit trail
* Event consumer edge function: `supabase/functions/event-consumer/index.ts`
* Automation executor edge function: `supabase/functions/automation-executor/index.ts`

**Event Flow:**

```
Database Trigger → publish_domain_event() → pg_notify(channel, payload)
  → Edge Function Listener → Process Event → Log to Audit
  → Future: Trigger Notifications/Automations/Webhooks
```

**Security:**

* All events include `organization_id` for tenant isolation
* Edge functions run with service role (no JWT verification)
* Event payloads logged for security audit
* No sensitive data (passwords, SSNs) in event payloads

**Idempotency and Retry (R7):**

* **Idempotency keys:** All event payloads MUST include a unique `event_id` (uuid); workflow executions MUST use `execution_id` as the idempotency key. Handlers in event-consumer and automation-executor MUST record processed keys and skip duplicates (e.g. check `fw_workflow_executions` or a processed-events table before performing side effects).
* **Retry/backoff:** On transient failure (5xx, timeout), retry with exponential backoff (e.g. 1s, 2s, 4s, max 3 retries). Do not retry on 4xx (except 429).
* **Duplicate detection:** When invoked more than once (retry, at-least-once delivery), handlers MUST detect already-processed `event_id` or `execution_id` and return success without re-executing; never create duplicate charges, notifications, or workflow steps.

## PHI-Safe Payload Guidance

For PF-10/PF-11 workflows and PM-16-style billing communications, payloads must be identifier-only:

* Allowed: system-generated UUIDs (`organization_id`, `patient_id`, `statement_id`, etc.)
* Disallowed: patient names, MRNs, DOBs, account numbers, or narrative PHI fields
* Resolve display details only through authorized API/UI lookups after permission/RLS validation
* Use PM-16 integration guidance as the reference implementation pattern

**Future Enhancements:**

* Event bus for higher throughput (Redis, RabbitMQ, Kafka)
* Event replay for debugging and recovery
* Event versioning for schema evolution
* Circuit breaker for failing event handlers
* Dead letter queue for failed events
* Event aggregation and analytics

***

## Supabase Realtime channel contracts

Channel contracts for Supabase Realtime (broadcast/presence) are documented here when they define cross-cutting semantics or multi-tenant rules. Implementations must enforce authorization at channel subscription time and align with RLS on application tables.

<h3 id="pf-73-realtime-channel">
  PF-73: Swim Lane Diagram collaborative realtime channel \\
</h3>

**Owner:** PF-73 (Workflow Builder with Swim Lane Visualization)\
**Status:** ✅ Implemented (Phase 2.2)\
**Spec:** [PF-73-workflow-builder-swim-lane-visualization.md](../../../specs/pf/specs/PF-73-workflow-builder-swim-lane-visualization.md)\
**Implemented:** 2026-03-14

**Hooks:**

* `useDiagramPresence(orgId, diagramId)` — wraps `useRealtimePresence` from `@/platform/realtime`
* `useDiagramBroadcast(orgId, diagramId)` — wraps `useRealtimeBroadcast`; event `diagram_updated`

**Broadcast payload:**

```typescript theme={null}
interface DiagramBroadcastPayload {
  type: 'diagram_updated';
  version: number;
  userId: string;
  displayName: string;
  timestamp: string;
}
```

**Channel schema:** `org:{orgId}:diagram:{diagramId}` — composite key; never use diagram id alone (prevents cross-tenant leakage).

**Semantics:** subscribe, broadcast, and presence (track) are allowed only after channel-level authorization. Authorization MUST be performed at channel subscription time (before allowing `subscribe()`, `broadcast()`, or `track()`/presence), not solely via RLS on application tables.

**Multi-tenant verification rules:**

* **Org-scoped auth:** Verify the requester belongs to `orgId` (e.g. via `pf_has_org_access(organization_id, auth.uid())`) before allowing join, broadcast, or presence on that channel.
* **RLS:** Diagram and version tables remain org-scoped; require RLS policies on `realtime.messages` (where applicable) plus an explicit server/edge check that verifies the requester belongs to `orgId`.
* **Documentation:** Channel-level checks and required RLS/auth checks are documented in [CROSS\_CORE\_INTEGRATIONS.md](./CROSS_CORE_INTEGRATIONS.md) and [PF-73-workflow-builder-swim-lane-INTEGRATION.md](./workflow-builder-swim-lane-integration.md).

***

## Implemented Events

### FW-03: Form Submission Events

**Event:** `automation_trigger` (form\_submitted / form\_updated)\
**Publisher:** FW (Forms & Workflow)\
**Subscribers:** FW-03 Automation Engine\
**Status:** ✅ Complete\
**Implemented:** 2025-11-25

**Payload Schema:**

```typescript theme={null}
{
  trigger_type: 'form_submitted' | 'form_updated';
  submission_id: uuid;
  form_id: uuid;
  organization_id: uuid;
  site_id?: uuid;
  submitted_by: uuid;
  submission_data: Record<string, any>;
  old_status?: submission_status;  // Only for updates
  new_status: submission_status;
}
```

**Implementation:**

```sql theme={null}
CREATE TRIGGER trigger_automation_on_submission
AFTER INSERT OR UPDATE ON fw_form_submissions
FOR EACH ROW
EXECUTE FUNCTION trigger_automation_on_submission();
```

**Consumer:** `supabase/functions/automation-executor/index.ts`

* Listens to `automation_trigger` channel via pg\_notify
* Fetches matching automation rules
* Evaluates conditions
* Executes actions (email, notification, webhook, record update)
* Logs execution to `fw_automation_logs`

**Testing:** ✅ Complete - All test cases passed

***

### HR-02: Credential Management Events

**Event 1:** `hr_credential_expired` (canonical)\
**Legacy alias (deprecated):** `credential_expired` — maintained for backward compatibility but should migrate to canonical name\
**Publisher:** HR (Workforce)\
**Subscribers:** Event Consumer (audit logging), HR-04 (Scheduling)\
**Status:** ✅ Complete\
**Implemented:** 2025-11-25

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'hr_credential_expired'; // Canonical name; legacy 'credential_expired' deprecated
  employee_id: uuid;
  credential_id: uuid;
  credential_type_id: uuid;
  expiration_date: date;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Implementation:**

```sql theme={null}
CREATE TRIGGER trigger_credential_expired
AFTER UPDATE ON hr_employee_credentials
FOR EACH ROW
WHEN (NEW.expiration_date < CURRENT_DATE AND 
      (OLD.expiration_date IS NULL OR OLD.expiration_date >= CURRENT_DATE))
EXECUTE FUNCTION publish_credential_expired();
-- Note: Function should publish as 'hr_credential_expired' (canonical), legacy name maintained for backward compatibility
```

**Event 2:** `hr_credential_verified` (canonical)\
**Legacy alias (deprecated):** `credential_verified` — maintained for backward compatibility but should migrate to canonical name\
**Payload Schema:**

```typescript theme={null}
{
  event_type: 'hr_credential_verified'; // Canonical name; legacy 'credential_verified' deprecated
  employee_id: uuid;
  credential_id: uuid;
  credential_type_id: uuid;
  verified_by: uuid;
  verified_at: timestamptz;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Implementation:**

```sql theme={null}
CREATE TRIGGER trigger_credential_verified
AFTER UPDATE ON hr_employee_credentials
FOR EACH ROW
WHEN (NEW.verification_status = 'verified' AND OLD.verification_status != 'verified')
EXECUTE FUNCTION publish_credential_verified();
-- Note: Function should publish as 'hr_credential_verified' (canonical), legacy name maintained for backward compatibility
```

**Consumer:** `supabase/functions/event-consumer/index.ts`

* Logs all events to `pf_audit_logs`
* Future handlers ready for notifications and alerts

**HR-04 Integration (Credential Blocking):**

* HR-04 Scheduling subscribes to `hr_credential_expired` events (canonical; legacy `credential_expired` alias supported for backward compatibility)
* When credential expires, employee is automatically blocked from shift assignment
* Blocking prevents scheduling until credential is renewed and verified
* Integration documented in HR-04 spec (Scheduling & Capacity)

**Implementation in HR-04:**

```sql theme={null}
-- HR-04: Block employee from scheduling when credential expires
CREATE OR REPLACE FUNCTION hr_block_employee_on_credential_expiry()
RETURNS TRIGGER AS $$
BEGIN
  -- Update employee scheduling eligibility
  UPDATE hr_employees
  SET scheduling_blocked = true,
      scheduling_block_reason = 'credential_expired', // Uses legacy event name for backward compatibility
      scheduling_blocked_at = now()
  WHERE id = NEW.employee_id
    AND organization_id = NEW.organization_id;
  
  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Subscribe to credential_expired events via edge function
-- Location: supabase/functions/hr-scheduling-credential-listener/index.ts
```

**Testing:** ✅ Complete - Events fire correctly on status changes

***

### HR-03: Onboarding & Offboarding Events

**Status:** ✅ Complete (base events), 📝 Planned (IT trigger events)\
**Implemented:** 2025-11-25 (base), 2026-01-02 (IT triggers spec)

#### Completion Events (✅ Implemented)

**Event 1:** `hr_onboarding_completed` (canonical name; legacy alias `onboarding_completed`)\
**Publisher:** HR (Workforce)\
**Subscribers:** Event Consumer (audit logging)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'hr_onboarding_completed'; // legacy: 'onboarding_completed'
  employee_id: uuid;
  onboarding_instance_id: uuid;
  completed_at: timestamptz;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Event 2:** `offboarding_completed`\
**Payload Schema:**

```typescript theme={null}
{
  event_type: 'offboarding_completed';
  employee_id: uuid;
  offboarding_instance_id: uuid;
  completed_at: timestamptz;
  termination_type: termination_type;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

#### IT Trigger Events (📝 Planned - IT-08 Integration)

These events trigger IT-08 IT Onboarding/Offboarding workflows.

**Event 3:** `hr_onboarding_started`\
**Publisher:** HR (Workforce)\
**Subscribers:** IT-08 (IT Provisioning)\
**Trigger:** INSERT on `hr_onboarding_instances`

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'hr_onboarding_started';
  employee_id: uuid;
  onboarding_instance_id: uuid;
  template_id: uuid;
  start_date: date;
  is_clinical: boolean;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Event 4:** `hr_onboarding_task_created`\
**Publisher:** HR (Workforce)\
**Subscribers:** IT-08 (IT Task Instance)\
**Trigger:** INSERT on `hr_onboarding_task_instances` WHERE category = 'it\_setup'

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'hr_onboarding_task_created';
  task_instance_id: uuid;
  onboarding_instance_id: uuid;
  employee_id: uuid;
  category: 'it_setup';
  title: string;
  due_date: date;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Event 5:** `hr_offboarding_started`\
**Publisher:** HR (Workforce)\
**Subscribers:** IT-08 (IT Offboarding)\
**Trigger:** INSERT on `hr_offboarding_instances`

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'hr_offboarding_started';
  employee_id: uuid;
  offboarding_instance_id: uuid;
  termination_date: date;
  termination_type: 'voluntary' | 'involuntary' | 'retirement' | 'end_contract';
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Event 6:** `hr_offboarding_task_created`\
**Publisher:** HR (Workforce)\
**Subscribers:** IT-08 (IT Access Revocation)\
**Trigger:** INSERT on `hr_offboarding_checklist_items` WHERE category = 'access\_revocation'

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'hr_offboarding_task_created';
  checklist_item_id: uuid;
  offboarding_instance_id: uuid;
  employee_id: uuid;
  category: 'access_revocation';
  title: string;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Consumer:** `supabase/functions/event-consumer/index.ts`

* Logs all events to `pf_audit_logs`
* IT-08 handlers create corresponding IT provisioning/offboarding instances

**Testing:** ✅ Complete (base events) - Events published on workflow completion

***

### HR-31: Policy Acknowledgment Events — ⛔ ARCHIVED

> **⛔ DEPRECATED (2026-03-26):** HR-31 has been consolidated into GR-01. The HR-31 tables (`hr_policies`, `hr_policy_distributions`, `hr_policy_acknowledgments`) were dropped in migration `20260326034722`. These event contracts are retained for historical reference only.

**Status:** ⛔ Archived — consolidated into GR-01\
**Spec:** [HR-31](../../../specs/hr/specs/HR-31-employee-document-policy-acknowledgment.md) (deprecated)\
**Integration:** [HR-31 Integration](./employee-document-policy-acknowledgment-integration.md) (archived)

#### Event 1: `hr_policy_acknowledgment_completed` (archived)

**Publisher:** HR-31 (dropped)\
**Subscribers:** None (historical only — no active subscribers)

**Payload Schema (historical):**

```typescript theme={null}
{
  event_type: 'hr_policy_acknowledgment_completed';
  acknowledgment_id: uuid;
  employee_id: uuid;
  policy_id: uuid;
  distribution_id: uuid;
  organization_id: uuid;
  acknowledged_at: timestamptz;
  timestamp: timestamptz;
}
```

**Idempotency:** `(organization_id, acknowledgment_id)`

#### Event 2: `hr_policy_distribution_created` (archived)

**Publisher:** HR-31 (dropped)\
**Subscribers:** None (historical only — no active subscribers)

**Payload Schema (historical):**

```typescript theme={null}
{
  event_type: 'hr_policy_distribution_created';
  distribution_id: uuid;
  policy_id: uuid;
  policy_title: string;
  employee_ids: uuid[];
  deadline_date: date;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Idempotency:** `(organization_id, distribution_id)`

#### Consumer: `hr_onboarding_completed` → HR-31 (archived)

> **Archived:** HR-31 previously consumed `hr_onboarding_completed` (HR-03) to create new-hire policy packet distributions. This consumer was removed when HR-31 was consolidated into GR-01. GR-01 now handles policy acknowledgment workflows directly.

***

### HR-05: Time & Attendance Exception Events

**Status:** ✅ Implemented\
**Implemented:** 2026-03-09

#### Event 1: `hr_timesheet_exception_created`

**Publisher:** HR (DB trigger on `hr_time_exceptions`)\
**Subscribers:** `time-exception-notify` edge function → PF-10 (in-app notification)\
**Channel:** `hr_events`\
**Trigger:** INSERT on `hr_time_exceptions`

**Payload Schema:**

```typescript theme={null}
interface HrTimesheetExceptionCreatedPayload {
  event_type: 'hr_timesheet_exception_created';
  exception_id: string;       // UUID
  employee_id: string;        // UUID
  exception_type: string;
  exception_date: string;     // ISO date
  organization_id: string;    // UUID — required for tenant isolation
  site_id?: string;           // UUID — optional site context
  timestamp: string;          // ISO 8601 timestamptz
  correlation_id?: string;    // UUID — optional for tracing
}
```

**Consumer:** `supabase/functions/time-exception-notify/index.ts`

* Resolves manager via `hr_employees.manager_id`
* Creates in-app notification via `createNotificationIfNew()` (dedup by reference)
* Notification type: `timesheet_exception`
* Auth gate: validates Authorization header before processing

***

### HR-10: Performance Management Events

**Status:** ✅ Implemented\
**Implemented:** 2026-01-13 (Event 1), 2026-01-12 (Event 3)

#### Event 1: `performance_review_completed`

**Publisher:** HR (Workforce)\
**Subscribers:** LO-03 (Goals), HR-15 (Compensation), HR-16 (Succession Planning)\
**Status:** ✅ Implemented (2026-01-13)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'performance_review_completed';
  review_id: uuid;
  employee_id: uuid;
  reviewer_id: uuid;
  overall_rating: 'exceeds_expectations' | 'meets_expectations' | 'below_expectations';
  review_period_start: date;
  review_period_end: date;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify other systems of completed reviews for goal alignment, compensation planning, succession planning

**Implementation:**

```sql theme={null}
CREATE TRIGGER trigger_performance_review_completed
  AFTER UPDATE ON public.hr_performance_reviews
  FOR EACH ROW
  EXECUTE FUNCTION public.hr_trigger_performance_review_completed();
```

#### Event 2: `performance_goal_completed`

**Publisher:** HR (Workforce)\
**Subscribers:** LO-03 (Goals)\
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'performance_goal_completed';
  goal_id: uuid;
  employee_id: uuid;
  organizational_goal_id: uuid | null;
  status: 'completed' | 'not_met';
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Update organizational goal progress when employee goals complete

#### Event 3: `hr_pip_terminated`

**Publisher:** HR (Workforce)\
**Subscribers:** HR-03 (Offboarding), HR-14 (Employee Relations)\
**Status:** ✅ Implemented (2026-01-12)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'hr_pip_terminated';
  pip_id: uuid;
  employee_id: uuid;
  organization_id: uuid;
  disciplinary_action_id: uuid;  // Created HR-14 record
  final_assessment: string;
  terminated_at: timestamptz;
}
```

**Purpose:** Trigger employee relations case and potential offboarding when PIP fails

**Implementation:**

* Hook: `src/cores/hr/hooks/performance/usePIPTerminationIntegration.ts`
* Event registered in: `fw_workflow_events` table
* Triggered by: `usePIPMutation.completePIP()` when outcome is 'unsuccessful'
* Creates: `hr_disciplinary_actions` record with `action_type: 'termination'`
* UI Warning: `PIPCompleteDialog.tsx` shows warning for unsuccessful outcome

**Consumer Actions:**

1. Creates disciplinary action record in HR-14
2. Publishes `hr_pip_terminated` event for workflow automation
3. Future: Triggers HR-03 offboarding workflow via automation rules

***

### HR-11 / HR-PAY-02: Benefit Enrollment Events (Payroll Deductions)

**Status:** 📝 Planned (Event payloads documented; publisher and HR-PAY-02 subscriber to be implemented)
**Spec Reference:** HR-PAY-02 (Payroll Deductions), HR-11 (Benefits Administration). When implemented, HR-PAY-02 will subscribe to auto-create deduction on enrollment and end-date deduction on termination. See `src/cores/hr/lib/reconcileEnrollmentDeductions.ts` for enrollment-deduction sync pattern.

> **⚠️ BREAKING CHANGE (v2.2.0):** The payloads for `hr.benefit_enrollment.created` and `hr.benefit_enrollment.terminated` were restructured:
>
> * **Removed:** `enrollment_id`, `benefit_plan_id`, `enrollment_date`, `coverage_tier`
> * **Added:** `benefit_enrollment_id`, `amount`, `pre_tax`
> * **Structure:** Event-specific fields moved into `payload` object per Event Schema Standard
>   Implementers consuming these events must update their handlers.

#### Event 1: `hr.benefit_enrollment.created`

**Publisher:** HR (Workforce) — HR-11 Benefits\
**Subscribers:** HR-PAY-02 (Payroll Deductions)

**Payload Schema:**

```typescript theme={null}
{
  event: 'hr.benefit_enrollment.created';
  payload: {
    employee_id: uuid;
    benefit_enrollment_id: uuid;
    amount: number;           // employee contribution amount for deduction
    pre_tax: boolean;
  };
  metadata: {
    organization_id: uuid;
    user_id?: uuid;
    timestamp: timestamptz;
    correlation_id?: uuid;
  };
}
```

**Purpose:** Notify payroll deductions (HR-PAY-02) of new benefit enrollment so a deduction can be auto-created.

#### Event 2: `hr.benefit_enrollment.terminated`

**Publisher:** HR (Workforce) — HR-11 Benefits\
**Subscribers:** HR-PAY-02 (Payroll Deductions)

**Payload Schema:**

```typescript theme={null}
{
  event: 'hr.benefit_enrollment.terminated';
  payload: {
    employee_id: uuid;
    benefit_enrollment_id: uuid;
    amount: number;           // last contribution amount (for reference)
    pre_tax: boolean;
  };
  metadata: {
    organization_id: uuid;
    user_id?: uuid;
    timestamp: timestamptz;
    correlation_id?: uuid;
  };
}
```

**Purpose:** Notify payroll deductions (HR-PAY-02) of benefit enrollment termination so the deduction can be end-dated.

***

### HR-PAY-04: Employer Tax Liability Events (Tax Forms Compliance)

**Status:** 📝 Planned (Publisher implemented; FA consumer not yet implemented)
**Publisher:** HR (Workforce) — HR-PAY-04 — ✅ Implemented in `src/cores/hr/services/employer-taxes/publish-tax-event.ts` (publishes to `hr_events`).
**Subscribers:** FA (Finance) — for GL posting and liability tracking. **Consumer:** Not yet implemented; until FA consumes this event, GL posting may be manual. See [FA\_FINANCIAL\_COMPLIANCE\_TRACKING.md](../../compliance/FA_FINANCIAL_COMPLIANCE_TRACKING.md).
**Spec Reference:** HR-PAY-04 (Tax Forms Compliance)

#### Event: `hr.employer_tax_liability.calculated`

**Publisher:** HR (Workforce) — HR-PAY-04\
**Subscribers:** FA (Finance) — for GL posting and liability tracking

**Payload Schema (Event Schema Standard):**

```typescript theme={null}
{
  event: 'hr.employer_tax_liability.calculated';
  payload: {
    organization_id: uuid;
    tax_period_type: 'quarterly' | 'annual';
    tax_period_start: date;
    tax_period_end: date;
    federal_income_tax_withheld: number;
    social_security_tax_withheld: number;
    medicare_tax_withheld: number;
    employer_ss_tax: number;
    employer_medicare_tax: number;
    additional_medicare_tax_withheld?: number;
    total_liability: number;
    tax_form_run_id?: uuid;
  };
  metadata: {
    organization_id: uuid;
    user_id?: uuid;
    timestamp: timestamptz;
    correlation_id?: uuid;
  };
}
```

**Purpose:** Notify FA when employer-side tax liability has been calculated so FA can post to GL (or queue for manual posting until FA automation is ready).

**Contingency:** Until FA is ready to consume this event, GL posting may be manual; document acceptance and link confirmation in HR-PAY-04 plan.

***

### HR-34: Contractor & Contingent Workforce Events

**Status:** 📝 Planned (Event stubs defined; publishers to be implemented in Phase 4)
**Publisher:** HR (Workforce) — HR-34
**Subscribers:** PF-10 (Notifications), FW-16 (Workflow automation — optional)
**Spec Reference:** [HR-34 Contractor & Contingent Workforce Management](../../../specs/hr/specs/HR-34-contractor-contingent-workforce-management.md)
**Channel:** `hr_events`

#### Event 1: `hr_contractor_created`

**Publisher:** HR (Workforce) — HR-34
**Subscribers:** PF-10 (Notifications), FW-16 (optional automation triggers)
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
{
  event: 'hr_contractor_created';
  payload: {
    organization_id: uuid;
    contractor_id: uuid;
    classification: string; // 'independent_contractor' | 'agency_contractor' | 'consultant' | 'temp_worker'
    agency_id?: uuid; // if agency_contractor
  };
  metadata: {
    organization_id: uuid;
    user_id: uuid;
    timestamp: timestamptz;
    correlation_id?: uuid;
  };
}
```

**Purpose:** Notify downstream systems when a new contractor is onboarded. No tax IDs in payload.

#### Event 2: `hr_contractor_contract_renewal_due`

**Publisher:** HR (Workforce) — HR-34
**Subscribers:** PF-10 (Notifications — renewal alerts to HR managers)
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
{
  event: 'hr_contractor_contract_renewal_due';
  payload: {
    organization_id: uuid;
    contractor_id: uuid;
    contract_id: uuid;
    end_date: date;
    renewal_notice_days: number; // days until expiration
  };
  metadata: {
    organization_id: uuid;
    timestamp: timestamptz;
    correlation_id?: uuid;
  };
}
```

**Purpose:** Alert HR managers when a contractor contract is approaching its end date. Fired by batch cron or on contract create/update. No tax IDs in payload.

#### Event 3: `hr_contractor_credential_expiring`

**Publisher:** HR (Workforce) — HR-34
**Subscribers:** PF-10 (Notifications — expiration alerts)
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
{
  event: 'hr_contractor_credential_expiring';
  payload: {
    organization_id: uuid;
    contractor_id: uuid;
    credential_id: uuid;
    expiration_date: date;
    days_until_expiration: number;
  };
  metadata: {
    organization_id: uuid;
    timestamp: timestamptz;
    correlation_id?: uuid;
  };
}
```

**Purpose:** Alert when a contractor credential is approaching expiration (30/60/90 day thresholds). Aligns with HR-02 credential expiration patterns. No tax IDs in payload.

***

### FA-12: Expense Management Events

**Status:** ✅ Implemented (Events 1-4 published in code)\
**Spec Reference:** specs/fa/specs/FA-12-expense-management-reimbursements.md

#### Event 1: `fa_expense_report_submitted` (canonical)

**Publisher:** FA (Finance)\
**Subscribers:** FW-03 (Approval Workflow), PF-10 (Notifications)\
**Status:** ✅ Implemented

**Payload Schema:**

```typescript theme={null}
interface ExpenseReportSubmittedEvent {
  event_version: '1.0';
  event_id: string;
  event_timestamp: string;
  organization_id: string;
  expense_report_id: string;
  employee_id: string;
  total_amount: number;
  submitted_at: string;
  submitted_by: string;
  line_count: number;
  has_policy_violations: boolean;
}
```

**SLA:** Delivery \< 500ms p95, Processing \< 2s p95, 3 retries with exponential backoff

**Purpose:** Trigger approval workflow for expense report

> **Note:** Canonical event name is `fa_expense_report_submitted`. This is the canonical schema for the event. Previous versions using `event_type` and simplified fields have been consolidated into this format. Consumers should migrate to use `ExpenseReportSubmittedEvent` interface fields.

#### Event 2: `fa_expense_report_approved` (canonical)

**Publisher:** FA (Finance)\
**Subscribers:** FA-05 (Payment Processing), PF-10 (Notifications)\
**Status:** ✅ Implemented

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fa_expense_report_approved'; // Canonical name
  event_id: uuid;
  event_version: '1.0';
  expense_report_id: uuid;
  report_number: string;
  employee_id: uuid;
  total_amount: number;
  approved_by: uuid;
  approved_at: timestamptz;
  approval_id: uuid;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Trigger reimbursement processing

> **Note:** Consumers (FA-05, PF-10) MUST use `event_id` for deduplication and retry handling. The `event_version` field enables schema evolution tracking.

#### Event 3: `fa_expense_report_rejected` (canonical)

**Publisher:** FA (Finance)\
**Subscribers:** PF-10 (Notifications)\
**Status:** ✅ Implemented

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fa_expense_report_rejected'; // Canonical name
  event_id: uuid;
  event_version: '1.0';
  expense_report_id: uuid;
  report_number: string;
  employee_id: uuid;
  rejected_at: timestamptz;
  rejected_by: uuid;
  rejection_reason: string;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify employee of rejection

> **Note:** Consumers (PF-10) MUST use `event_id` for deduplication and retry handling. The `event_version` field enables schema evolution tracking.

#### Event 4: `fa_reimbursement_processed` (canonical)

**Publisher:** FA (Finance)\
**Subscribers:** FA-02 (GL), PF-10 (Notifications)\
**Status:** ✅ Implemented

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fa_reimbursement_processed'; // Canonical name
  event_id: uuid;
  event_version: '1.0';
  reimbursement_payment_id: uuid;
  payment_number: string;
  employee_id: uuid;
  payment_amount: number;
  journal_entry_id: uuid;
  processed_by: uuid;
  processed_at: timestamptz;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify reimbursement completion and trigger GL posting

> **Note:** Consumers (FA-02, PF-10) MUST use `event_id` for deduplication and retry handling. The `event_version` field enables schema evolution tracking.

***

### HR-14: Employee Relations Events

**Status:** ✅ Complete\
**Implemented:** 2026-01-09

#### Event 1: `disciplinary_action_termination`

**Publisher:** HR (Workforce)\
**Subscribers:** HR-03 (Offboarding), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'disciplinary_action_termination';
  disciplinary_action_id: uuid;
  employee_id: uuid;
  action_type: 'termination';
  termination_reason: string;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Trigger HR-03 offboarding workflow when disciplinary action results in termination

#### Event 2: `incident_reported`

**Publisher:** HR (Workforce)\
**Subscribers:** GR-06 (Incident Management), PF-10 (Notifications for critical/serious)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'incident_reported';
  incident_id: uuid;
  incident_type: 'accident' | 'injury' | 'safety_violation' | 'property_damage' | 'other';
  severity: 'minor' | 'moderate' | 'serious' | 'critical';
  incident_date: date;
  organization_id: uuid;
  site_id?: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify GR-06 incident management system of workplace incidents

#### Event 3: `grievance_filed`

**Publisher:** HR (Workforce)\
**Subscribers:** GR-03 (Compliance)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'grievance_filed';
  grievance_id: uuid;
  employee_id: uuid;
  grievance_type: 'harassment' | 'discrimination' | 'wage_dispute' | 'working_conditions' | 'other';
  filed_date: date;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify compliance team of employee grievances for tracking and resolution

***

### HR-26: E-Verify Integration Events

**Status:** ✅ Implemented\
**Publisher:** HR-26 (E-Verify orchestrator edge function)\
**Subscribers:** PF-10 (notifications), audit log

**Event 1:** `hr_everify_case_created`\
**Trigger:** Successful USCIS case creation via `hr-everify-orchestrator`\
**Payload:**

```typescript theme={null}
{
  case_id: uuid;
  employee_id: uuid;
  uscis_case_number: string;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Event 2:** `hr_everify_status_changed`\
**Trigger:** Status transition on poll or manual update\
**Payload:**

```typescript theme={null}
{
  case_id: uuid;
  employee_id: uuid;
  old_status: string;
  new_status: string;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Event 3:** `hr_everify_tnc_opened`\
**Trigger:** Case enters TNC state\
**Payload:**

```typescript theme={null}
{
  case_id: uuid;
  employee_id: uuid;
  tnc_type: string;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

***

**Status:** ✅ Complete\
**Implemented:** 2026-01-13

#### Event 1: `merit_increase_approved`

**Publisher:** HR (Workforce)\
**Subscribers:** HR-07 (Payroll), FA (Budget tracking), PF-10 (Notifications)\
**Trigger:** `hr_merit_increases.status` → `'approved'`

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'merit_increase_approved';
  merit_increase_id: uuid;
  employee_id: uuid;
  current_salary: number;
  new_salary: number;
  increase_percentage: number;
  effective_date: date;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify payroll and finance of approved salary changes

#### Event 2: `compensation_analysis_completed`

**Publisher:** HR (Workforce)\
**Subscribers:** FA (Analytics), PF-10 (Notifications)\
**Trigger:** `hr_compensation_analyses.status` → `'approved'`

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'compensation_analysis_completed';
  analysis_id: uuid;
  analysis_type: 'internal_equity' | 'market_comparison' | 'distribution';
  disparity_percent: number;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify finance of equity analysis results for budgeting decisions

#### Event 3: `compensation_cost_allocated`

**Publisher:** HR (Workforce)\
**Subscribers:** FA (Budget adjustments), FA (Cost forecasting)\
**Trigger:** `hr_merit_increases.status` → `'approved'`

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'compensation_cost_allocated';
  source: 'hr_merit_increases';
  merit_increase_id: uuid;
  employee_id: uuid;
  employee_name: string;
  department_id: uuid | null;
  department_name: string | null;
  position_title: string | null;
  previous_salary: number;
  new_salary: number;
  increase_amount: number;
  increase_percentage: number;
  annual_cost_impact: number;
  effective_date: date;
  currency: string;
  organization_id: uuid;
  approved_by: uuid;
  approved_at: timestamptz;
  timestamp: timestamptz;
}
```

**Consumer Actions:**

1. FA creates budget alert for significant cost increases
2. FA updates departmental expense forecasts
3. FA may trigger budget amendment workflow if over threshold

**Testing:** Verify event fires on merit increase approval with correct payload

***

### HR-16: Succession Planning Events

**Status:** 📝 Planned\
**Implemented:** TBD

#### Event 1: `successor_identified`

**Publisher:** HR (Workforce)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'successor_identified';
  succession_plan_id: uuid;
  position_id: uuid;
  successor_id: uuid;
  readiness_level: 'ready_now' | 'ready_1_year' | 'ready_2_years' | 'ready_3_plus_years';
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify managers of successor readiness

#### Event 2: `talent_promoted`

**Publisher:** HR (Workforce)\
**Subscribers:** HR-16 (Succession Planning)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'talent_promoted';
  employee_id: uuid;
  from_position_id: uuid;
  to_position_id: uuid;
  promotion_date: date;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Update succession plans when talent is promoted

***

### HR-17: Employee Engagement Events

**Status:** 📝 Planned\
**Implemented:** TBD

#### Event 1: `survey_completed`

**Publisher:** HR (Workforce)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'survey_completed';
  survey_id: uuid;
  response_id: uuid;
  employee_id: uuid | null; // null if anonymous
  completion_percentage: number;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify managers of survey completion for tracking participation

#### Event 2: `exit_interview_completed`

**Publisher:** HR (Workforce)\
**Subscribers:** HR-03 (Offboarding)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'exit_interview_completed';
  exit_interview_id: uuid;
  employee_id: uuid;
  offboarding_instance_id: uuid;
  reason_for_leaving: string;
  would_recommend: boolean;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Update offboarding workflow when exit interview completed

***

### FA-02: Vendor Bill Approved Events

**Event:** `vendor_bill_approved`\
**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FW-03 (Workflow completion), PF-10 (Notifications), FA-03 (Payment queue)\
**Status:** ✅ Complete\
**Implemented:** 2025-11-26

**Payload Schema:**

```typescript theme={null}
{
  bill_id: uuid;
  bill_number: string;
  vendor_id: uuid;
  vendor_name: string;
  total_amount: number;
  due_date: date;
  approved_by: uuid;
  approved_at: timestamp;
  approval_workflow_id?: uuid;
  organization_id: uuid;
  site_id?: uuid;
}
```

**Consumer:**

* `supabase/functions/event-consumer/index.ts` - Logs to audit trail
* FW-03 Automation Engine - Completes approval workflow steps
* PF-10 Notifications - Notifies vendors and accounting team
* FA-03 Payment Processing - Queues bill for payment

**Testing:** ✅ Complete - Event fires on bill approval

***

### FA-03: Payment Processed Events

**Event:** `payment_processed`\
**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-02 (GL posting), PF-10 (Vendor notification), FA-06 (Bank reconciliation)\
**Status:** ✅ Complete\
**Implemented:** 2025-11-26

**Payload Schema:**

```typescript theme={null}
{
  payment_id: uuid;
  payment_number: string;
  vendor_id: uuid;
  payment_amount: number;
  payment_date: date;
  payment_method: 'check' | 'ach' | 'wire' | 'card';
  check_number?: string;
  bank_account_id: uuid;
  applied_bills: [{
    bill_id: uuid;
    amount_applied: number;
  }];
  organization_id: uuid;
  processed_by: uuid;
  processed_at: timestamp;
}
```

**Consumer:**

* FA-02 Chart of Accounts - Creates GL journal entry for payment
* PF-10 Notifications - Sends payment confirmation to vendor
* FA-06 Bank Reconciliation - Marks expected transaction for reconciliation

**Testing:** ✅ Complete - Event fires on payment creation with bill applications

***

### FA-03: Vendor Activated (domain event)

**Registry ID:** FA-E-06 (`vendor_activated`)\
**Event name:** `fa.vendor.activated`\
**Version:** `1.0.0`\
**Publisher:** FA (Finance & Accounting) — vendor master activation (e.g. [FA-UX-11 Vendor onboarding wizard](../../../specs/fa/ux/FA-UX-11-vendor-onboarding-wizard.md))\
**Status:** 📝 Planned\
**Spec reference (single source of truth):** [FA-03 Accounts Payable — Event Contracts — FA-E-06](../../../specs/fa/specs/FA-03-accounts-payable.md) (naming, versioning, payload)

**Publish call pattern:**

```typescript theme={null}
publish_domain_event('fa.vendor.activated', { version: '1.0.0', payload });
```

**Payload schema (`payload` object):**

```typescript theme={null}
{
  vendor_id: uuid;
  organization_id: uuid;
  created_by_user_id: uuid;
  classification: '1099-MISC' | '1099-NEC' | null; // public 1099 categorization only; no TIN/bank data
  has_portal_invite: boolean;
  is_active: boolean;
  notes?: string; // optional; non-sensitive summary only — must NOT include vendor contact details (emails, phone numbers), TIN or partial TIN fragments, bank account/routing numbers or hints, insurance policy numbers, health/medical identifiers, or any other PII/PHI/secrets subject to compliance
}
```

**Purpose:** Notify async consumers (indexing, search, cross-core integrations) after a vendor is activated, without exposing sensitive vendor credentials in the event stream.

***

### FA-22: Accounts Payable Automation Events

**Spec Reference:** specs/fa/specs/FA-22-accounts-payable-automation.md\
**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FW-16 (Workflow Events – workflow triggers). Subscribers must subscribe to event\_type values `fa_bill_scan_completed` and `fa_bill_duplicate_flagged`.\
**Status:** 📝 Planned\
**Channel:** `fa_events` (or equivalent)

#### fa\_bill\_scan\_completed

**Event type:** `fa_bill_scan_completed`\
**When:** After fa-scan-invoice edge function completes and inserts into fa\_invoice\_scans.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fa_bill_scan_completed';
  organization_id: uuid;      // Required
  timestamp: timestamptz;     // Required
  user_id?: uuid;            // When user-initiated (e.g. scan from UI)
  correlation_id?: string;   // When chaining with other events
  scan_id: uuid;
  vendor_bill_id: uuid | null;  // Set when linked to bill
  confidence_score: number;
}
```

#### fa\_bill\_duplicate\_flagged

**Event type:** `fa_bill_duplicate_flagged`\
**When:** After fa-detect-duplicates creates a fa\_duplicate\_detection\_log entry (on bill insert or cron).

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fa_bill_duplicate_flagged';
  organization_id: uuid;     // Required
  timestamp: timestamptz;     // Required
  user_id?: uuid;            // When user-initiated
  correlation_id?: string;   // When chaining (e.g. from same batch)
  vendor_bill_id: uuid;
  suspected_duplicate_of_id: uuid;
  match_score: number;
  match_reason: string;
  log_id: uuid;
}
```

**Integration:** FW-16 Event Registry – register event\_type values `fa_bill_scan_completed` and `fa_bill_duplicate_flagged` so workflow designers can trigger automations (e.g., notify approver when duplicate flagged).

***

### FA-04: Purchase Order Events

**Status:** ✅ Complete\
**Implemented:** 2026-01-27\
**Spec Reference:** specs/fa/specs/FA-04-purchase-orders.md

#### FA-E-04: purchase\_order\_approved

**Event:** `purchase_order_approved`\
**Publisher:** FA (Finance & Accounting)\
**Subscribers:** Event Consumer (audit logging), PF-10 (Notifications), FA-11 (Fixed Assets - asset creation from PO)\
**Status:** ✅ Complete\
**Channel:** `fa_events`

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'purchase_order_approved';
  po_id: uuid;
  po_number: string;
  vendor_id: uuid;
  po_total: number;
  approved_by: uuid;
  approved_at: timestamp;
  user_id: uuid;  // Mirrors approved_by for user-initiated actions
  organization_id: uuid;
  site_id?: uuid;
  timestamp: timestamptz;
}
```

**Consumer:**

* `supabase/functions/event-consumer/index.ts` - Logs to audit trail
* PF-10 Notifications - Notifies purchaser and receiving staff
* FA-11 Fixed Assets - Creates asset records from PO (when implemented)

**Trigger:** Database trigger `fa_publish_po_approved()` fires when PO status changes to 'approved'

**Testing:** ✅ Complete - Event fires on PO approval

***

#### FA-E-05: goods\_received

**Event:** `goods_received`\
**Publisher:** FA (Finance & Accounting)\
**Subscribers:** Event Consumer (audit logging), PF-10 (Notifications), FA-11 (Fixed Assets - asset receipt)\
**Status:** ✅ Complete\
**Channel:** `fa_events`

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'goods_received';
  receipt_id: uuid;
  receipt_number: string;
  po_id: uuid;
  po_number: string;
  receipt_date: date;
  received_by: uuid;
  user_id: uuid;  // Mirrors received_by for user-initiated actions
  organization_id: uuid;
  site_id?: uuid;
  timestamp: timestamptz;
}
```

**Consumer:**

* `supabase/functions/event-consumer/index.ts` - Logs to audit trail
* PF-10 Notifications - Notifies AP staff for bill matching
* FA-11 Fixed Assets - Updates asset status to "received" (when implemented)

**Trigger:** Database trigger `fa_publish_goods_received()` fires on receipt creation

**Testing:** ✅ Complete - Event fires on receipt creation

***

### FA-02: Journal Entry Posted Events

**Event:** `journal_entry_posted`\
**Publisher:** FA (Finance & Accounting)\
**Subscribers:** Event Consumer (audit logging), FA-07 (Balance refresh), PF-10 (Notifications)\
**Status:** ✅ Complete\
**Implemented:** 2025-11-26

**Payload Schema:**

```typescript theme={null}
{
  journal_entry_id: uuid;
  entry_number: string;
  entry_date: date;
  description: string;
  total_debit: number;
  total_credit: number;
  status: 'posted';
  source: 'manual' | 'accounts_payable' | 'payroll' | 'accounts_receivable' | 'bank_import';
  source_document_id?: uuid;
  fiscal_period_id: uuid;
  organization_id: uuid;
  posted_by: uuid;
  posted_at: timestamp;
  lines: [{
    account_id: uuid;
    fund_id?: uuid;
    department_id?: uuid;
    debit: number;
    credit: number;
  }];
}
```

**Consumer:**

* Event Consumer - Logs all posted journal entries to audit trail
* FA-07 Financial Reporting - Refreshes account balances and financial statements
* PF-10 Notifications - Alerts accounting team of significant postings

**Testing:** ✅ Complete - Event fires on journal entry posting with all line details

***

### FA-08: Budget Approved Events

**Event:** `budget_approved`\
**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FW-03 (Workflow completion), PF-10 (Notifications), FA-07 (Reporting)\
**Status:** ✅ Complete\
**Implemented:** 2025-11-26

**Payload Schema:**

```typescript theme={null}
{
  budget_id: uuid;
  budget_name: string;
  fiscal_year: number;
  fund_id?: uuid;
  department_id?: uuid;
  total_amount: number;
  approved_by: uuid;
  approved_at: timestamp;
  approval_level: number;
  organization_id: uuid;
}
```

**Consumer:**

* FW-03 Automation Engine - Completes approval workflow
* PF-10 Notifications - Notifies budget owners and finance team
* FA-07 Financial Reporting - Enables budget vs. actual reporting

**Testing:** ✅ Complete - Event fires on budget approval

***

### FA-08: Budget Exceeded Events

**Event:** `budget_exceeded`\
**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications to budget owners), FA-08 (Alert log)\
**Status:** ✅ Complete\
**Implemented:** 2025-11-26

**Payload Schema:**

```typescript theme={null}
{
  budget_id: uuid;
  budget_name: string;
  account_id: uuid;
  account_number: string;
  fund_id?: uuid;
  department_id?: uuid;
  budget_amount: number;
  actual_amount: number;
  variance_percent: number;
  threshold_type: 'warning' | 'critical';
  organization_id: uuid;
  triggered_by_entry_id: uuid;
  triggered_at: timestamp;
}
```

**Consumer:**

* PF-10 Notifications - Sends alerts to budget owners and finance managers
* FA-08 Budget Management - Logs alert and tracks budget compliance

**Testing:** ✅ Complete - Event fires when budget threshold exceeded

***

### FA-09: Consolidation Completed Events

**Event:** `consolidation_completed`\
**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-07 (Consolidated reports), PF-10 (Notifications), Event Consumer (audit)\
**Status:** ✅ Complete\
**Implemented:** 2025-11-26

**Payload Schema:**

```typescript theme={null}
{
  consolidation_id: uuid;
  consolidation_name: string;
  as_of_date: date;
  entities_included: uuid[];
  total_eliminations: number;
  elimination_amount: number;
  consolidated_assets: number;
  consolidated_liabilities: number;
  consolidated_net_assets: number;
  parent_organization_id: uuid;
  completed_by: uuid;
  completed_at: timestamp;
}
```

**Consumer:**

* FA-07 Financial Reporting - Generates consolidated financial statements
* PF-10 Notifications - Alerts management of completed consolidation
* Event Consumer - Logs consolidation completion to audit trail

**Testing:** ✅ Complete - Event fires on consolidation run completion

***

### PM-05: Provider Time-Off Events

**Owning Core:** PM (Practice Management)\
**Spec:** [PM-05 Provider Schedule & Availability](../../../specs/pm/specs/PM-05-provider-schedule-availability.md)\
**Integration:** [PM-05-provider-schedule-availability-INTEGRATION.md](./provider-schedule-availability-integration.md)\
**Status:** ✅ Implemented (2026-02-20) — declared in INTEGRATION doc; canonical schemas registered here on 2026-05-04 during PM-05 pre-verification.

All three events use canonical naming `pm_{entity}_{action}` and carry IDs only — no PHI. Subscribers must dereference IDs through PM RLS-protected reads.

#### `pm_time_off_requested`

**Publisher:** PM-05 (on insert into `pm_provider_time_off` with `status = 'pending'`)\
**Subscribers:** PF-10 Notifications (notify approver), FW (workflow triggers), Event Consumer (audit)\
**Schema version:** 1

```json theme={null}
{
  "event_type": "pm_time_off_requested",
  "schema_version": 1,
  "payload": {
    "organization_id": "uuid",
    "provider_id": "uuid",
    "time_off_id": "uuid",
    "start_date": "YYYY-MM-DD",
    "end_date": "YYYY-MM-DD",
    "time_off_type": "vacation | sick | personal | continuing_education | conference | other"
  }
}
```

#### `pm_time_off_approved`

**Publisher:** PM-05 (on update to `pm_provider_time_off.status = 'approved'`)\
**Subscribers:** PM-03 (refresh availability), PM-04 (refresh facilitator availability), PF-10 (notify provider + coverage), HR-04 (display only — no shared tables), Event Consumer (audit)\
**Schema version:** 1

```json theme={null}
{
  "event_type": "pm_time_off_approved",
  "schema_version": 1,
  "payload": {
    "organization_id": "uuid",
    "provider_id": "uuid",
    "time_off_id": "uuid",
    "approved_by": "uuid",
    "coverage_provider_id": "uuid | null"
  }
}
```

#### `pm_time_off_denied`

**Publisher:** PM-05 (on update to `pm_provider_time_off.status = 'denied'`)\
**Subscribers:** PF-10 (notify requester), Event Consumer (audit)\
**Schema version:** 1

```json theme={null}
{
  "event_type": "pm_time_off_denied",
  "schema_version": 1,
  "payload": {
    "organization_id": "uuid",
    "provider_id": "uuid",
    "time_off_id": "uuid",
    "denied_by": "uuid"
  }
}
```

**PHI safety:** None of the three payloads contain patient data. `time_off_type` is workforce metadata, not clinical PHI.\
**Idempotency:** Subscribers SHOULD treat `time_off_id` as the idempotency key.\
**Registration TODO:** Verify these three events are seeded in `fw_workflow_events` (producer=`pm`). If absent, add a follow-up migration; if the shipped PM-05 hooks do not currently call `publishEvent`, this section documents the contract for the upcoming wiring.

***

### CL-57: Clinical Content Marketplace Events

#### `cl_marketplace_bundle_imported`

**Publisher:** CL-57 (`cl-marketplace-import` Edge Function on successful import)
**Subscribers:** Event Consumer (audit), future content-distribution analytics
**Status:** ✅ Implemented
**Schema version:** 1

```json theme={null}
{
  "event_type": "cl_marketplace_bundle_imported",
  "schema_version": 1,
  "payload": {
    "event_id": "uuid",
    "organization_id": "uuid",
    "import_id": "uuid",
    "bundle_id": "uuid",
    "bundle_key": "string",
    "bundle_version": "integer",
    "imported_item_count": "integer",
    "unsupported_item_count": "integer"
  }
}
```

**PHI safety:** Marketplace content is platform-curated reference data (no patient identifiers). All payload fields are tenant + bundle metadata only.
**Publishing semantics:** Event publishes only after the import transaction has been materialized for the tenant (`cl_marketplace_imports` marked `completed` and import outputs persisted). Publisher authorization for curator actions is gated by `cl_can_curate_marketplace()` per CL-57.
**Idempotency:** `event_id` is the canonical deduplication key for cross-retry processing (Event Schema Standard). `import_id` remains the domain-specific idempotency key for marketplace import workflows and subscriber reconciliation.
**Retry semantics:** Fire-and-forget from the import flow. A publish failure does NOT roll back the import (the per-org rows are already materialized and survive event-bus outages).
**Versioning/consumers:** Consumers should branch on `schema_version`; current consumers are audit/event-observability pipelines, with downstream analytics consumers planned.
**Spec reference:** [CL-57 Clinical Content Marketplace](../../../specs/cl/specs/CL-57-clinical-content-marketplace.md)

***

### CL-31: Co-Occurring Disorder Integrated Documentation — No Events Published

**Status:** ⚪ Not Applicable (intentional)
**Publisher:** None (CL-31 is an intra-CL extension)
**Subscribers:** None

CL-31 (Co-Occurring Disorder Integrated Documentation) extends CL-02 (assessments), CL-03 (treatment plans), and CL-04 (progress notes) **in-place** and does **not publish any domain events** in Phase 1 or Phase 2. Rationale:

* 42 CFR Part 2 SUD redaction is enforced at **request time** via `cl_check_sud_consent()` and `redactSUDFields()` in `@/platform/clinical`, not via async event consumers.
* All COD integration with downstream cores (PM billing, CL-15 quality measures) flows through existing CL-02/CL-03/CL-04 events; no new event surface is introduced.
* ASAM COD level is informational only; no PM service-authorization event coupling (Clarification #12).

If a future phase introduces a domain event (e.g., `cl_cod_assessment_completed` for CL-15 quality reporting), it MUST be added here with full schema, PHI-safety review, and a CONTEXT.md decision record.

**Spec reference:** [CL-31 Co-Occurring Disorder Integrated Documentation](../../../specs/cl/specs/CL-31-co-occurring-disorder-integrated-documentation.md)

***

## Planned Events (LO-14/15 Action Dependencies & Status)

### LO-14: Action Unblocked Event

**Event:** `action_unblocked`\
**Publisher:** LO (Leadership Operating System)\
**Subscribers:** PF-10 (Notifications), Event Consumer (audit logging)\
**Status:** 📝 Planned\
**Spec Reference:** [LO-14 Action Dependencies](../../../specs/lo/specs/LO-14-action-dependencies.md)

**Purpose:** Notify when a dependency action completes, enabling dependent actions to proceed.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'action_unblocked';
  action_id: uuid;          // The action that was unblocked
  goal_id: uuid;            // The parent goal (rock_id)
  organization_id: uuid;
  site_id?: uuid;
  dependency_action_id: uuid; // The action that was completed
  unblocked_at: timestamptz;
  unblocked_by_user_id?: uuid; // User who completed the dependency
  timestamp: timestamptz;
}
```

**Consumer Actions:**

* Event Consumer: Log to `pf_audit_logs` for audit trail
* PF-10 Notifications (Future): Send notification to action assignee

**Implementation (Planned):**

```sql theme={null}
-- Trigger when an action completes that has dependent actions
CREATE OR REPLACE FUNCTION lo_publish_action_unblocked()
RETURNS TRIGGER AS $$
DECLARE
  v_dependent_action RECORD;
BEGIN
  -- Only fire when action is completed
  IF NEW.status = 'complete' AND (OLD.status IS NULL OR OLD.status != 'complete') THEN
    -- Find actions that depend on this action
    FOR v_dependent_action IN
      SELECT id, rock_id, organization_id
      FROM lo_rock_milestones
      WHERE depends_on_action_id = NEW.id
    LOOP
      PERFORM pg_notify('lo_events', json_build_object(
        'event_type', 'action_unblocked',
        'action_id', v_dependent_action.id,
        'goal_id', v_dependent_action.rock_id,
        'organization_id', v_dependent_action.organization_id,
        'dependency_action_id', NEW.id,
        'unblocked_at', now(),
        'unblocked_by_user_id', auth.uid(),
        'timestamp', now()
      )::text);
    END LOOP;
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER SET search_path = public;
```

***

### LO-15: Action Status Changed Event

**Event:** `action_status_changed`\
**Publisher:** LO (Leadership Operating System)\
**Subscribers:** PF-10 (Notifications), Event Consumer (audit logging)\
**Status:** 📝 Planned\
**Spec Reference:** [LO-15 Enhanced Action Status](../../../specs/lo/specs/LO-15-enhanced-action-status.md)

**Purpose:** Notify when an action's status changes, enabling audit logging and status-based notifications.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'action_status_changed';
  action_id: uuid;
  goal_id: uuid;            // The parent goal (rock_id)
  organization_id: uuid;
  site_id?: uuid;
  old_status: 'not_started' | 'in_progress' | 'blocked' | 'on_hold' | 'needs_review' | 'complete';
  new_status: 'not_started' | 'in_progress' | 'blocked' | 'on_hold' | 'needs_review' | 'complete';
  changed_by: uuid;
  changed_at: timestamptz;
  timestamp: timestamptz;
}
```

**Consumer Actions:**

* Event Consumer: Log to `pf_audit_logs` for audit trail
* PF-10 Notifications (Future): Send notifications based on status:
  * `needs_review` → Notify reviewer/goal owner
  * `blocked` → Notify assignee and goal owner
  * `complete` → Notify goal owner

**Implementation (Planned):**

```sql theme={null}
CREATE OR REPLACE FUNCTION lo_publish_action_status_changed()
RETURNS TRIGGER AS $$
BEGIN
  IF OLD.status IS DISTINCT FROM NEW.status THEN
    PERFORM pg_notify('lo_events', json_build_object(
      'event_type', 'action_status_changed',
      'action_id', NEW.id,
      'goal_id', NEW.rock_id,
      'organization_id', NEW.organization_id,
      'old_status', COALESCE(OLD.status, 'not_started'),
      'new_status', NEW.status,
      'changed_by', auth.uid(),
      'changed_at', now(),
      'timestamp', now()
    )::text);
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER SET search_path = public;

CREATE TRIGGER trigger_action_status_changed
AFTER UPDATE ON lo_rock_milestones
FOR EACH ROW
WHEN (OLD.status IS DISTINCT FROM NEW.status)
EXECUTE FUNCTION lo_publish_action_status_changed();
```

***

## Planned Events (FW-22 Execution Monitoring)

### FW-22: Workflow Execution Failed Event

**Event:** `execution_failed`\
**Publisher:** FW (Forms & Workflow)\
**Subscribers:** PF-10 (Notifications), FW-22 (Monitoring Dashboard)\
**Status:** 📝 Planned (FW-22 Implementation)\
**Spec Reference:** [FW-22 Workflow Execution Monitoring & Debugging](../../../specs/fw/archive/FW-22-workflow-execution-monitoring.md)

**Purpose:** Notify when a workflow execution fails, enabling alerts and monitoring dashboard updates.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'execution_failed';
  organization_id: uuid;
  site_id?: uuid;
  execution_id: uuid;
  workflow_id: uuid;
  workflow_name: string;
  failed_node_id?: string;
  failed_node_name?: string;
  error_message: string;
  error_code?: string;
  started_at: timestamptz;
  failed_at: timestamptz;
  trigger_type: 'form_submitted' | 'form_updated' | 'scheduled' | 'manual' | 'event';
  triggered_by?: uuid;
  timestamp: timestamptz;
}
```

**Consumer Actions:**

* PF-10 Notifications: Send alert to workflow owner and org admins
* FW-22 Dashboard: Update failed execution count, trigger refresh

**Implementation (Planned):**

```sql theme={null}
CREATE TRIGGER trigger_execution_failed
AFTER UPDATE ON fw_workflow_executions
FOR EACH ROW
WHEN (NEW.status = 'failed' AND OLD.status != 'failed')
EXECUTE FUNCTION publish_execution_failed();
```

***

## Planned Events (FW-32 External Form Portal)

### FW-16-P2: Event Schema Updated

**Event:** `fw_event_schema_updated`\
**Publisher:** FW (Forms & Workflow)\
**Subscribers:** FW (Event Registry UI), Monitoring\
**Status:** ✅ Implemented (FW-16-P2)\
**Channel:** `fw_events`

```typescript theme={null}
{
  event_type: 'fw_event_schema_updated';
  organization_id: uuid;
  payload: {
    event_name: string;
    old_schema_version: number;
    new_schema_version: number;
    changed_by: uuid;
  };
}
```

***

### FW-16-P2: Event Deprecated

**Event:** `fw_event_deprecated`\
**Publisher:** FW (Forms & Workflow)\
**Subscribers:** FW (Event Registry UI), Monitoring\
**Status:** ✅ Implemented (FW-16-P2)\
**Channel:** `fw_events`

```typescript theme={null}
{
  event_type: 'fw_event_deprecated';
  organization_id: uuid;
  payload: {
    event_name: string;
    deprecated_at: string;
    replacement_event: string | null;
    deprecated_by: uuid;
  };
}
```

***

### FW-32: External Form Submission Event

**Event:** `fw_external_form_submitted`\
**Publisher:** FW (Forms & Workflow)\
**Subscribers:** PF-10 (Notifications), FW-03 (Automation Engine)\
**Status:** ✅ Implemented (FW-32 — published by `portal-form-submit` edge function via `pg_notify`)\
**Spec Reference:** [FW-32 External Form Portal](../../../specs/fw/archive/FW-32-external-form-portal.md)

**Purpose:** Notify when a form is submitted via the external portal, trigger notifications and workflow automations.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fw_external_form_submitted';
  organization_id: uuid;
  site_id?: uuid;
  form_id: uuid;
  submission_id: uuid;
  portal_config_id: uuid;
  submitted_at: timestamptz;
  submitted_by_email: string;
  verified: boolean;
  spam_score?: number;
  timestamp: timestamptz;
}
```

**Consumer Actions:**

* PF-10 Notifications: Send confirmation email to submitter
* FW-03 Automation Engine: Trigger any workflow automations configured for external form submissions

**Implementation (Planned):**

```sql theme={null}
CREATE OR REPLACE FUNCTION fw_publish_external_form_submitted()
RETURNS TRIGGER AS $$
DECLARE
  v_portal_config fw_form_portal_config;
BEGIN
  -- Get portal config
  SELECT * INTO v_portal_config
  FROM fw_form_portal_config
  WHERE form_id = NEW.form_id
    AND organization_id = NEW.organization_id
    AND is_active = true
  LIMIT 1;
  
  IF v_portal_config IS NOT NULL THEN
    PERFORM pg_notify('fw_events', json_build_object(
      'event_type', 'fw_external_form_submitted',
      'organization_id', NEW.organization_id,
      'site_id', NEW.site_id,
      'form_id', NEW.form_id,
      'submission_id', NEW.id,
      'portal_config_id', v_portal_config.id,
      'submitted_at', NEW.submitted_at,
      'submitted_by_email', NEW.submitted_by_email,
      'verified', NEW.email_verified,
      'spam_score', NEW.spam_score,
      'timestamp', now()
    )::text);
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER trigger_external_form_submitted
AFTER INSERT ON fw_form_submissions
FOR EACH ROW
WHEN (NEW.submitted_via = 'portal')
EXECUTE FUNCTION fw_publish_external_form_submitted();
```

***

## Planned Events (FW-34 Approval Workflows)

### FW-34: Approval Request Submitted Event

**Event:** `fw_approval_submitted`\
**Publisher:** FW (Forms & Workflow)\
**Subscribers:** PF-10 (Notifications), FW-03 (Automation Engine)\
**Status:** 📝 Planned (FW-34 Implementation)\
**Spec Reference:** [FW-34 Approval Workflows](../../../specs/fw/archive/FW-34-approval-workflows.md)

**Purpose:** Notify when a new approval request is submitted, trigger notifications to approvers.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fw_approval_submitted';
  organization_id: uuid;
  site_id?: uuid;
  request_id: uuid;
  chain_id: uuid;
  title: string;
  submitted_by: uuid;
  source_type: 'form_submission' | 'entity' | 'workflow';
  source_id: uuid;
  priority: 'low' | 'normal' | 'high' | 'urgent';
  timestamp: timestamptz;
}
```

**Consumer Actions:**

* PF-10 Notifications: Send notification to assigned approvers
* FW-03 Automation Engine: Trigger any related automations

**Implementation (Planned):**

```sql theme={null}
CREATE OR REPLACE FUNCTION fw_publish_approval_submitted()
RETURNS TRIGGER AS $$
BEGIN
  PERFORM pg_notify('fw_events', json_build_object(
    'event_type', 'fw_approval_submitted',
    'organization_id', NEW.organization_id,
    'request_id', NEW.id,
    'chain_id', NEW.chain_id,
    'title', NEW.title,
    'submitted_by', NEW.submitted_by,
    'source_type', NEW.source_type,
    'source_id', NEW.source_id,
    'priority', NEW.priority,
    'timestamp', now()
  )::text);
  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER trigger_approval_submitted
AFTER INSERT ON fw_approval_requests
FOR EACH ROW
EXECUTE FUNCTION fw_publish_approval_submitted();
```

***

### FW-34: Approval Request Completed Event

**Event:** `fw_approval_completed`\
**Publisher:** FW (Forms & Workflow)\
**Subscribers:** FW-03 (Automation Engine), PF-10 (Notifications)\
**Status:** 📝 Planned (FW-34 Implementation)\
**Spec Reference:** [FW-34 Approval Workflows](../../../specs/fw/archive/FW-34-approval-workflows.md)

**Purpose:** Notify when an approval request is completed (approved or rejected).

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fw_approval_completed';
  organization_id: uuid;
  site_id?: uuid;
  request_id: uuid;
  chain_id: uuid;
  title: string;
  decision: 'approved' | 'rejected';
  submitted_by: uuid;
  completed_by: uuid;
  source_type: 'form_submission' | 'entity' | 'workflow';
  source_id: uuid;
  completed_at: timestamptz;
  timestamp: timestamptz;
}
```

**Consumer Actions:**

* FW-03 Automation Engine: Trigger post-approval automations (e.g., update entity status)
* PF-10 Notifications: Notify submitter of decision

**Implementation (Planned):**

```sql theme={null}
CREATE OR REPLACE FUNCTION fw_publish_approval_completed()
RETURNS TRIGGER AS $$
BEGIN
  IF NEW.status IN ('approved', 'rejected') AND 
     (OLD.status IS NULL OR OLD.status NOT IN ('approved', 'rejected')) THEN
    PERFORM pg_notify('fw_events', json_build_object(
      'event_type', 'fw_approval_completed',
      'organization_id', NEW.organization_id,
      'request_id', NEW.id,
      'chain_id', NEW.chain_id,
      'title', NEW.title,
      'decision', NEW.final_decision,
      'submitted_by', NEW.submitted_by,
      'completed_by', NEW.completed_by,
      'source_type', NEW.source_type,
      'source_id', NEW.source_id,
      'completed_at', NEW.completed_at,
      'timestamp', now()
    )::text);
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER trigger_approval_completed
AFTER UPDATE ON fw_approval_requests
FOR EACH ROW
EXECUTE FUNCTION fw_publish_approval_completed();
```

***

### FW-34: Approval Escalated Event

**Event:** `fw_approval_escalated`\
**Publisher:** FW (Forms & Workflow)\
**Subscribers:** PF-10 (Notifications)\
**Status:** 📝 Planned (FW-34 Implementation)\
**Spec Reference:** [FW-34 Approval Workflows](../../../specs/fw/archive/FW-34-approval-workflows.md)

**Purpose:** Notify when an approval is escalated due to timeout.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fw_approval_escalated';
  organization_id: uuid;
  request_id: uuid;
  assignment_id: uuid;
  original_assignee_id: uuid;
  escalated_to_id?: uuid;
  reason: 'timeout' | 'manual';
  hours_overdue: number;
  timestamp: timestamptz;
}
```

**Consumer Actions:**

* PF-10 Notifications: Notify escalation target and original approver

***

## Planned Events (FW-33 Form Signature Capture)

### FW-33: Form Signature Captured Event

**Event:** `fw_form_signature_captured`\
**Publisher:** FW (Forms & Workflow)\
**Subscribers:** FW-03 (Automation Engine), PF-10 (Notifications)\
**Status:** 📝 Planned (FW-33 Implementation)\
**Spec Reference:** [FW-33 Form Signature Capture](../../../specs/fw/archive/FW-33-form-signature-capture.md)

**Purpose:** Notify when a signature is captured on a form field, trigger automations and notifications.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fw_form_signature_captured';
  organization_id: uuid;
  site_id?: uuid;
  form_id: uuid;
  submission_id: uuid;
  field_id: uuid;
  signature_id: uuid; // References pf_signatures (PF-33)
  signer_user_id?: uuid;
  signer_email: string;
  timestamp: timestamptz;
}
```

**Consumer Actions:**

* FW-03 Automation Engine: Trigger signature-based workflow automations
* PF-10 Notifications: Send confirmation to signer

***

### FW-33: Signed Document Generated Event

**Event:** `fw_signed_document_generated`\
**Publisher:** FW (Forms & Workflow)\
**Subscribers:** PF-11 (Documents)\
**Status:** 📝 Planned (FW-33 Implementation)\
**Spec Reference:** [FW-33 Form Signature Capture](../../../specs/fw/archive/FW-33-form-signature-capture.md)

**Purpose:** Notify when a signed PDF document is generated from a form submission.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'fw_signed_document_generated';
  organization_id: uuid;
  submission_id: uuid;
  document_id: uuid; // References pf_documents (PF-11)
  signature_ids: uuid[]; // All signatures embedded in document
  generated_at: timestamptz;
  timestamp: timestamptz;
}
```

**Consumer Actions:**

* PF-11 Documents: Link document to submission, update document metadata

***

## Planned Events (FW-16 Event Registry)

The following events are planned for registration in `fw_workflow_events` as part of FW-16 (Event-Based Workflow Triggers):

### HR Core Events (Planned)

| Event Name                                    | Display Name                   | Category    | Entity Type                   |
| --------------------------------------------- | ------------------------------ | ----------- | ----------------------------- |
| `hr_employee_created`                         | Employee Created (canonical)   | lifecycle   | hr\_employees                 |
| `hr_employee_assigned_to_site`                | Employee Assigned to Site      | lifecycle   | hr\_employees                 |
| `hr_employee_hired`                           | Employee Hired                 | lifecycle   | hr\_employees                 |
| `hr_employee_terminated`                      | Employee Terminated            | lifecycle   | hr\_employees                 |
| `hr_credential_expired`                       | Credential Expired             | compliance  | hr\_employee\_credentials     |
| `hr_credential_verified`                      | Credential Verified            | compliance  | hr\_employee\_credentials     |
| `hr_onboarding_completed`                     | Onboarding Completed           | lifecycle   | hr\_onboarding\_instances     |
| `hr_leave_approved`                           | Leave Approved                 | operational | hr\_leave\_requests           |
| `hr_interview_scorecard_assigned`             | Scorecard Assigned             | operational | hr\_interview\_scorecards     |
| `hr_interview_scorecard_submitted`            | Scorecard Submitted            | operational | hr\_interview\_scorecards     |
| `hr_final_paycheck_status_changed`            | Final Paycheck Status Changed  | compliance  | hr\_final\_paycheck\_requests |
| `hr_fingerprint_clearance_status_changed`     | Clearance Status Changed       | compliance  | hr\_fingerprint\_clearances   |
| `hr_fingerprint_clearance_expiration_warning` | Clearance Expiration Warning   | compliance  | hr\_fingerprint\_clearances   |
| `hr_flsa_classification_changed`              | FLSA Classification Changed    | compliance  | hr\_flsa\_classifications     |
| `hr_flsa_reclassification_approved`           | FLSA Reclassification Approved | compliance  | hr\_flsa\_reclassifications   |

> **HR-01 canonical events (confirmed 2026-04-28):** `hr_employee_created`, `hr_employee_assigned_to_site`, and `hr_employee_terminated` are published by HR-01 — see [HR-01 Integration §Events](./employee-directory-integration.md) for full payload schemas. `hr_employee_hired` is treated as a synonym/legacy alias of `hr_employee_created` for downstream consumers (FW-16 registry retains both names during transition; new subscribers SHOULD prefer `hr_employee_created`). Subscribers include PF-101 (Google Workspace provisioning/offboarding), HR-30 (final paycheck on termination), and FW-16 workflow triggers.

### PF-101: Google Workspace Integration (planned detail)

**Spec:** [PF-101](../../../specs/pf/specs/PF-101-google-workspace-integration.md)
**Integration:** [PF-101 Integration](./google-workspace-integration-integration.md)

**Consumes:**

* `hr_employee_created` (HR-01) — provision or link a Google Workspace user when tenant policy enables provisioning. Payload: `organization_id`, `employee_id`, `profile_id`, `department_id`, `position_id`, `hire_date`, `correlation_id`, `timestamp`.
* `hr_employee_assigned_to_site` (HR-01) — reconcile site-based group, OU, Drive, Calendar resource, or Chat mappings. Payload: `organization_id`, `employee_id`, `site_id`, `assignment_date`, `role`, `correlation_id`, `timestamp`.
* `hr_employee_terminated` (HR-01) — suspend/offboard linked Workspace user, revoke licenses, remove groups, queue Drive transfer review. Payload: `organization_id`, `employee_id`, `termination_date`, `termination_reason`, `correlation_id`, `timestamp`.

**Publishes:**

* `pf_google_workspace_user_provisioned` — subscribers PF-10, HR status consumers; payload: `organization_id`, `employee_id`, `profile_id`, `google_user_id`, `correlation_id`, `timestamp`. Signals successful Workspace user provisioning without exposing secrets or PHI. Subscribers requiring email must perform scoped lookups using `google_user_id` or `profile_id`.
* `pf_google_workspace_connector_degraded` — subscribers PF-10, PF-36; payload: `organization_id`, `connection_id`, `capability` (`directory|gmail|calendar|drive|chat|licensing|reports`), `reason_code` (sanitized machine code), `correlation_id`, `timestamp`. Alerts admins when credential, scope, quota, BAA gate, or sync health degrades.

| Event Name                               | Display Name                        | Category  | Entity Type                        |
| ---------------------------------------- | ----------------------------------- | --------- | ---------------------------------- |
| `pf_google_workspace_user_provisioned`   | Google Workspace User Provisioned   | lifecycle | pf\_google\_workspace\_user\_links |
| `pf_google_workspace_connector_degraded` | Google Workspace Connector Degraded | health    | pf\_google\_workspace\_connections |

See [PF-101 Integration §Event Contracts](./google-workspace-integration-integration.md) for full payload schemas, BAA/PHI-gating rules, and idempotency semantics (events keyed by `event_id` as the canonical deduplication key; `correlation_id` is used only for trace/linkage).

### HR-28: Fingerprint Clearance Card Management (planned detail)

**Spec:** [HR-28](../../../specs/hr/specs/HR-28-fingerprint-clearance-card-management.md)\
**Publishes:**

* `hr_fingerprint_clearance_status_changed` — notify HR-02, HR-03 gates when clearance moves between blocking/non-blocking states; payload: `organization_id`, `employee_id`, `clearance_id`, `previous_status`, `new_status`, `effective_at`.
* `hr_fingerprint_clearance_expiration_warning` — scheduled worker fires at 90/60/30-day thresholds; subscriber PF-10; payload: `organization_id`, `employee_id`, `clearance_id`, `days_until_expiration`, `expiration_date`.

See [HR-28 Integration](./fingerprint-clearance-card-management-integration.md) for full payload schemas.

### HR-29: FLSA Classification & Compliance Engine (planned detail)

**Spec:** [HR-29](../../../specs/hr/specs/HR-29-flsa-classification-compliance-engine.md)
**Publishes:**

* `hr_flsa_classification_changed` — subscribers HR-07 (Payroll), HR-01 (Employee Directory); payload: `classification_id`, `position_id`, `employee_id`, `previous_classification`, `new_classification`, `effective_date`, `retroactive_start_date`, `retroactive_pay_request_id`, `organization_id`.
* `hr_flsa_reclassification_approved` — subscribers HR-07 (Payroll); payload: `reclassification_id`, `employee_id`, `new_classification`, `effective_date`, `retroactive_start_date`, `retroactive_pay_request_id`, `organization_id`.

See [HR-29 Integration](./flsa-classification-integration.md) for full payload schemas and data flow.

### HR-30: Final paycheck (planned detail)

**Spec:** [HR-30](../../../specs/hr/specs/HR-30-final-paycheck-termination-pay-compliance.md)\
**Consumes:** `hr_employee_terminated` (HR-03) — create `hr_final_paycheck_requests`.\
**May publish:** `hr_final_paycheck_status_changed` — subscribers PF-10, HR-07 (Phase 2); payload stub in [HR-30 Integration](./final-paycheck-termination-pay-compliance-integration.md).

### RH Core Events (Planned)

| Event Name               | Display Name           | Category    | Entity Type         |
| ------------------------ | ---------------------- | ----------- | ------------------- |
| `rh_resident_admitted`   | Resident Admitted      | lifecycle   | rh\_episodes        |
| `rh_resident_discharged` | Resident Discharged    | lifecycle   | rh\_episodes        |
| `rh_phase_advanced`      | Episode phase advanced | operational | rh\_episode\_phases |
| `rh_bed_assigned`        | Bed Assigned           | operational | rh\_beds            |

### FA Core Events (Planned)

| Event Name             | Display Name      | Category  | Entity Type            |
| ---------------------- | ----------------- | --------- | ---------------------- |
| `fa_invoice_paid`      | Invoice Paid      | financial | fa\_invoices           |
| `fa_budget_approved`   | Budget Approved   | financial | fa\_budgets            |
| `fa_budget_exceeded`   | Budget Exceeded   | alert     | fa\_budget\_alerts     |
| `fa_payment_processed` | Payment Processed | financial | fa\_customer\_payments |

**Implementation:** See [FW-16 Event-Based Workflow Triggers](../../../specs/fw/archive/FW-16-event-based-workflow-triggers.md) for full specification.

***

### FA-10: Tax Reporting Events

**Status:** 📝 Planned\
**Spec Reference:** FA-10 (Tax Reporting & Compliance)

#### Event 1: `tax_1099_generated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'tax_1099_generated';
  organization_id: uuid;
  tax_year_id: uuid;
  vendor_id: uuid;
  form_type: '1099-MISC' | '1099-NEC';
  generated_at: timestamp;
}
```

#### Event 2: `tax_w2_generated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications), HR-07

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'tax_w2_generated';
  organization_id: uuid;
  tax_year_id: uuid;
  employee_id: uuid;
  generated_at: timestamp;
}
```

#### Event 3: `tax_year_closed`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications), FA-07

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'tax_year_closed';
  organization_id: uuid;
  tax_year_id: uuid;
  tax_year: number;
  closed_at: timestamp;
  closed_by: uuid;
}
```

***

### FA-11: Fixed Assets Events

**Status:** 📝 Planned\
**Spec Reference:** FA-11 (Fixed Assets & Depreciation)

#### Event 1: `asset_created`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FM-05 (Facilities), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'asset_created';
  organization_id: uuid;
  asset_id: uuid;
  asset_tag: string;
  asset_name: string;
  purchase_cost: number;
  created_at: timestamp;
}
```

#### Event 2: `asset_disposed`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FM-05 (Facilities), PF-10 (Notifications), FA-02 (GL)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'asset_disposed';
  organization_id: uuid;
  asset_id: uuid;
  disposal_date: date;
  disposal_method: string;
  gain_loss: number;
}
```

#### Event 3: `depreciation_posted`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-02 (GL), FA-07 (Financial Reporting)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'depreciation_posted';
  organization_id: uuid;
  asset_id: uuid;
  depreciation_month: date;
  depreciation_amount: number;
  journal_entry_id: uuid;
}
```

***

### FA-12: Expense Management Events

**Status:** 📝 Planned\
**Spec Reference:** FA-12 (Expense Management & Reimbursements)

> **Note:** The canonical schema for FA-12 events is defined in the FA-12 section above (lines 484-582). This duplicate section has been removed. Please refer to the `ExpenseReportSubmittedEvent` interface and other event definitions in that section for the authoritative payload formats.

***

### FA-13: Project Accounting Events

**Status:** 📝 Planned\
**Spec Reference:** FA-13 (Project Accounting & Grant Tracking)

#### Event 1: `project_created`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-08 (Budgeting), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'project_created';
  organization_id: uuid;
  project_id: uuid;
  project_number: string;
  project_name: string;
  created_at: timestamp;
}
```

#### Event 2: `project_budget_exceeded`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications), FA-08 (Budgeting)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'project_budget_exceeded';
  organization_id: uuid;
  project_id: uuid;
  budget_variance: number;
  exceeded_percentage: number;
}
```

#### Event 3: `grant_drawdown_received`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-02 (GL), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'grant_drawdown_received';
  organization_id: uuid;
  project_id: uuid;
  drawdown_id: uuid;
  drawdown_amount: number;
  received_at: timestamp;
}
```

***

### FA-14: Cash Management Events

**Status:** 📝 Planned\
**Spec Reference:** FA-14 (Cash Management & Treasury)

#### Event 1: `cash_position_updated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-07 (Financial Reporting), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'cash_position_updated';
  organization_id: uuid;
  position_date: date;
  total_cash: number;
  updated_at: timestamp;
}
```

#### Event 2: `investment_maturity_approaching`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'investment_maturity_approaching';
  organization_id: uuid;
  investment_id: uuid;
  maturity_date: date;
  days_until_maturity: number;
}
```

#### Event 3: `credit_limit_approaching`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'credit_limit_approaching';
  organization_id: uuid;
  credit_line_id: uuid;
  utilization_percentage: number;
  available_credit: number;
}
```

***

### FA-15: Cost Allocation Events

**Status:** 📝 Planned\
**Spec Reference:** FA-15 (Cost Allocation & Indirect Cost Rates)

#### Event 1: `idc_rate_calculated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-13 (Project Accounting), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'idc_rate_calculated';
  organization_id: uuid;
  rate_id: uuid;
  pool_id: uuid;
  fiscal_year: number;
  idc_rate: number;
  calculated_at: timestamp;
}
```

#### Event 2: `idc_allocated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-13 (Project Accounting), FA-02 (GL)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'idc_allocated';
  organization_id: uuid;
  allocation_id: uuid;
  project_id: uuid;
  allocated_idc: number;
  journal_entry_id: uuid;
}
```

***

### FA-16: Financial Analytics Events

**Status:** 📝 Planned\
**Spec Reference:** FA-16 (Financial Analytics & Dashboards)

#### Event 1: `kpi_threshold_exceeded`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'kpi_threshold_exceeded';
  organization_id: uuid;
  kpi_id: uuid;
  kpi_name: string;
  kpi_value: number;
  threshold_type: 'warning' | 'critical';
  exceeded_at: timestamp;
}
```

***

### FA-17: Intercompany Events

**Status:** 📝 Planned\
**Spec Reference:** FA-17 (Intercompany Transactions)

#### Event 1: `intercompany_transaction_created`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-02 (GL), FA-09 (Consolidation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'intercompany_transaction_created';
  organization_id: uuid;
  transaction_id: uuid;
  from_entity_id: uuid;
  to_entity_id: uuid;
  transaction_amount: number;
  created_at: timestamp;
}
```

#### Event 2: `intercompany_elimination_generated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-09 (Consolidation), FA-02 (GL)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'intercompany_elimination_generated';
  organization_id: uuid;
  elimination_id: uuid;
  consolidation_id: uuid;
  elimination_amount: number;
  generated_at: timestamp;
}
```

***

### FA-19: Financial Close Events

**Status:** 📝 Planned\
**Spec Reference:** FA-19 (Financial Close Management)

#### Event 1: `close_period_started`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications), FA-02 (GL)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_period_started';
  organization_id: uuid;
  close_period_id: uuid;
  period_name: string;
  started_at: timestamp;
}
```

#### Event 2: `close_period_completed`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications), FA-07 (Financial Reporting)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_period_completed';
  organization_id: uuid;
  close_period_id: uuid;
  period_name: string;
  completed_at: timestamp;
}
```

#### Event 3: `close_task_assigned`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_task_assigned';
  organization_id: uuid;
  close_task_id: uuid;
  assigned_to: uuid;
  assigned_at: timestamp;
}
```

***

### FA-10: Tax Reporting Events

**Status:** 📝 Planned\
**Spec Reference:** FA-10 (Tax Reporting & Compliance)

#### Event 1: `tax_1099_generated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'tax_1099_generated';
  organization_id: uuid;
  tax_year_id: uuid;
  vendor_id: uuid;
  form_type: '1099-MISC' | '1099-NEC';
  generated_at: timestamp;
}
```

#### Event 2: `tax_w2_generated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications), HR-07

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'tax_w2_generated';
  organization_id: uuid;
  tax_year_id: uuid;
  employee_id: uuid;
  generated_at: timestamp;
}
```

#### Event 3: `tax_year_closed`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications), FA-07

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'tax_year_closed';
  organization_id: uuid;
  tax_year_id: uuid;
  tax_year: number;
  closed_at: timestamp;
  closed_by: uuid;
}
```

***

### FA-11: Fixed Assets Events

**Status:** 📝 Planned\
**Spec Reference:** FA-11 (Fixed Assets & Depreciation)

#### Event 1: `asset_created`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FM-05 (Facilities), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'asset_created';
  organization_id: uuid;
  asset_id: uuid;
  asset_tag: string;
  asset_name: string;
  purchase_cost: number;
  created_at: timestamp;
}
```

#### Event 2: `asset_disposed`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FM-05 (Facilities), PF-10 (Notifications), FA-02 (GL)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'asset_disposed';
  organization_id: uuid;
  asset_id: uuid;
  disposal_date: date;
  disposal_method: string;
  gain_loss: number;
}
```

#### Event 3: `depreciation_posted`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-02 (GL), FA-07 (Financial Reporting)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'depreciation_posted';
  organization_id: uuid;
  asset_id: uuid;
  depreciation_month: date;
  depreciation_amount: number;
  journal_entry_id: uuid;
}
```

***

### FA-12: Expense Management Events

**Status:** 📝 Planned\
**Spec Reference:** FA-12 (Expense Management & Reimbursements)

> **Note:** The canonical schema for FA-12 events is defined in the FA-12 section above (lines 484-582). This duplicate section has been removed. Please refer to the `ExpenseReportSubmittedEvent` interface and other event definitions in that section for the authoritative payload formats.

***

### FA-13: Project Accounting Events

**Status:** 📝 Planned\
**Spec Reference:** FA-13 (Project Accounting & Grant Tracking)

#### Event 1: `project_created`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-08 (Budgeting), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'project_created';
  organization_id: uuid;
  project_id: uuid;
  project_number: string;
  project_name: string;
  created_at: timestamp;
}
```

#### Event 2: `project_budget_exceeded`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications), FA-08 (Budgeting)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'project_budget_exceeded';
  organization_id: uuid;
  project_id: uuid;
  budget_variance: number;
  exceeded_percentage: number;
}
```

#### Event 3: `grant_drawdown_received`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-02 (GL), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'grant_drawdown_received';
  organization_id: uuid;
  project_id: uuid;
  drawdown_id: uuid;
  drawdown_amount: number;
  received_at: timestamp;
}
```

***

### FA-14: Cash Management Events

**Status:** 📝 Planned\
**Spec Reference:** FA-14 (Cash Management & Treasury)

#### Event 1: `cash_position_updated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-07 (Financial Reporting), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'cash_position_updated';
  organization_id: uuid;
  position_date: date;
  total_cash: number;
  updated_at: timestamp;
}
```

#### Event 2: `investment_maturity_approaching`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'investment_maturity_approaching';
  organization_id: uuid;
  investment_id: uuid;
  maturity_date: date;
  days_until_maturity: number;
}
```

#### Event 3: `credit_limit_approaching`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'credit_limit_approaching';
  organization_id: uuid;
  credit_line_id: uuid;
  utilization_percentage: number;
  available_credit: number;
}
```

***

### FA-15: Cost Allocation Events

**Status:** 📝 Planned\
**Spec Reference:** FA-15 (Cost Allocation & Indirect Cost Rates)

#### Event 1: `idc_rate_calculated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-13 (Project Accounting), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'idc_rate_calculated';
  organization_id: uuid;
  rate_id: uuid;
  pool_id: uuid;
  fiscal_year: number;
  idc_rate: number;
  calculated_at: timestamp;
}
```

#### Event 2: `idc_allocated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-13 (Project Accounting), FA-02 (GL)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'idc_allocated';
  organization_id: uuid;
  allocation_id: uuid;
  project_id: uuid;
  allocated_idc: number;
  journal_entry_id: uuid;
}
```

***

### FA-16: Financial Analytics Events

**Status:** 📝 Planned\
**Spec Reference:** FA-16 (Financial Analytics & Dashboards)

#### Event 1: `kpi_threshold_exceeded`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'kpi_threshold_exceeded';
  organization_id: uuid;
  kpi_id: uuid;
  kpi_name: string;
  kpi_value: number;
  threshold_type: 'warning' | 'critical';
  exceeded_at: timestamp;
}
```

***

### FA-17: Intercompany Events

**Status:** 📝 Planned\
**Spec Reference:** FA-17 (Intercompany Transactions)

#### Event 1: `intercompany_transaction_created`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-02 (GL), FA-09 (Consolidation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'intercompany_transaction_created';
  organization_id: uuid;
  transaction_id: uuid;
  from_entity_id: uuid;
  to_entity_id: uuid;
  transaction_amount: number;
  created_at: timestamp;
}
```

#### Event 2: `intercompany_elimination_generated`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-09 (Consolidation), FA-02 (GL)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'intercompany_elimination_generated';
  organization_id: uuid;
  elimination_id: uuid;
  consolidation_id: uuid;
  elimination_amount: number;
  generated_at: timestamp;
}
```

***

### FA-18: Revenue Recognition Events

**Status:** ✅ Implemented (FA-18 Phase 2 WS3, 2026-04-25)\
**Spec Reference:** FA-18 (Revenue Recognition Advanced)

#### Event 1: `fa_revenue_recognized`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-02 (GL), FA-05 (AR), FA-13 (Projects)

**Payload Schema:**

```typescript theme={null}
{
  event_name: 'fa_revenue_recognized';
  organization_id: uuid;
  recognition_id: uuid;
  revenue_schedule_id: uuid;
  revenue_contract_id: uuid;
  fiscal_period_id: uuid;
  recognition_date: date;     // processing date
  recognition_amount: number;
  journal_entry_id: uuid | null;
  journal_entry_line_id: uuid | null;
  auto_posted: boolean;
  user_id: uuid | null;
  timestamp: string;          // ISO-8601
}
```

**Notes:** Published atomically with the `fa_revenue_recognitions` insert by `fa_process_revenue_recognition` (writes to `fw_domain_events`). `journal_entry_*` populated only when both revenue & deferred accounts resolve (schedule → contract → module defaults). `auto_posted` reflects `fa_module_settings.auto_post_revenue_recognition`. Canonical narrative: [FA-18-revenue-recognition-advanced-INTEGRATION.md](./revenue-recognition-advanced-integration.md).

#### Event 2: `fa_revenue_schedule_completed`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** FA-05 (AR), FA-13 (Projects), LO (Leadership OS metrics)

**Payload Schema:**

```typescript theme={null}
{
  event_name: 'fa_revenue_schedule_completed';
  organization_id: uuid;
  revenue_schedule_id: uuid;
  revenue_contract_id: uuid;
  total_revenue_amount: number;
  total_recognized: number;
  completed_at: string;       // ISO-8601
  user_id: uuid | null;
  timestamp: string;
}
```

**Notes:** Emitted in the same transaction as the recognition that drives the schedule's running total to within tolerance of `total_revenue_amount`. Tolerance comes from `fa_module_settings.revenue_recognition_sum_tolerance` (default 0.01).

***

### FA-19: Financial Close Events

**Status:** 📝 Planned\
**Spec Reference:** FA-19 (Financial Close Management)

#### Event 1: `close_period_started`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications), FA-02 (GL)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_period_started';
  organization_id: uuid;
  close_period_id: uuid;
  period_name: string;
  started_at: timestamp;
}
```

#### Event 2: `close_period_completed`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications), FA-07 (Financial Reporting)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_period_completed';
  organization_id: uuid;
  close_period_id: uuid;
  period_name: string;
  completed_at: timestamp;
}
```

#### Event 3: `close_task_assigned`

**Publisher:** FA (Finance & Accounting)\
**Subscribers:** PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_task_assigned';
  organization_id: uuid;
  close_task_id: uuid;
  assigned_to: uuid;
  assigned_at: timestamp;
}
```

***

### LO Core: Leadership Operating System Events

#### LO-01: Vision & Strategic Planning Events

**Event:** `rock_completed`
**Publisher:** LO (Leadership Operating System)
**Subscribers:** FA (Finance - financial goals), PF-10 (Notifications), PF-04 (Audit)
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'rock_completed';
  organization_id: uuid;
  rock_id: uuid;
  completed_date: date;
  owner_id: uuid;
  strategic_goal_id?: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify when Rock is completed (may trigger financial goals)

***

#### LO-04: To-Dos & Task Management Events

**Event 1:** `todo_created`\
**Publisher:** LO (Leadership Operating System)\
**Subscribers:** PF-10 (Notifications)\
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'todo_created';
  organization_id: uuid;
  todo_id: uuid;
  title: string;
  assigned_to: uuid;
  assigned_by: uuid;
  due_date?: date;
  rock_id?: uuid;
  issue_id?: uuid;
  meeting_id?: uuid;
  timestamp: timestamptz;
}
```

**Event 2:** `todo_completed`\
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'todo_completed';
  organization_id: uuid;
  todo_id: uuid;
  completed_date: date;
  assigned_to: uuid;
  rock_id?: uuid;
  timestamp: timestamptz;
}
```

**Event 3:** `todo_overdue`\
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'todo_overdue';
  organization_id: uuid;
  todo_id: uuid;
  title: string;
  assigned_to: uuid;
  due_date: date;
  days_overdue: number;
  timestamp: timestamptz;
}
```

***

#### LO-05: Scorecards & KPI Tracking Events

**Event 1:** `scorecard_updated`\
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

**Event 2:** `metric_threshold_breached`\
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

***

#### LO-06: Structured Meetings Events

**Event 1:** `meeting_scheduled`\
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

**Event 2:** `meeting_completed`\
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

**Event 3:** `action_item_created`\
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

***

#### LO-07: Issues & Problem Solving Events

**Event 1:** `issue_identified`\
**Status:** ✅ Complete

**Event 2:** `issue_resolved`\
**Status:** ✅ Complete

***

#### LO-09: Assessments & Surveys Events

**Event 1:** `assessment_distributed`\
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

**Event 2:** `assessment_completed`\
**Status:** ✅ Complete\
**Implemented:** 2025-12-03

***

## Planned Events

### RH-01: Resident Admission Events

**Event (canonical):** `rh_resident_admitted`\
**Deprecated alias:** `resident_admitted` (do not use in new code)
**Publisher:** RH (Recovery Housing)
**Subscribers:** FA (Finance & Revenue), PM (POS derivation for charge capture)
**Persistence:** `fw_domain_events` (SECURITY DEFINER trigger on `rh_episodes`)
**Status:** 🟡 Implemented (DB persistence); FA/PM batch consumers 📋 Planned
**Spec Reference:** [RH-01 Census, Beds & Episodes](../../../specs/rh/specs/RH-01-census-beds-episodes.md) · [RH-01.1 Bed Board & Facility Types](../../../specs/rh/specs/RH-01.1-bed-board-facility-types.md)
**Integration Doc:** [RH-01-bed-board-census-INTEGRATION.md](./bed-board-census-integration.md)

**Payload Schema:**

```typescript theme={null}
{
  event_name: 'rh_resident_admitted';
  timestamp: string;             // ISO 8601 / timestamptz
  organization_id: string;       // UUID
  site_id?: string;              // UUID — site-scoped when applicable
  correlation_id?: string;       // UUID — when event chaining
  episode_id: string;            // UUID — episode-based model
  resident_profile_id: string;   // UUID
  residence_id: string;          // UUID
  bed_id: string;                // UUID
  admission_date: string;        // ISO date
  user_id: string;               // UUID — staff member who performed the admission (audit/accountability)
  // facility_type is used by PM to derive Place of Service:
  //   recovery_housing       → POS 55 (Residential SUD)
  //   psychiatric_residential → POS 56 (Psychiatric residential / RTC / BHRF)
  //   inpatient_unit          → POS 51 (Inpatient psychiatric)
  facility_type: 'recovery_housing' | 'psychiatric_residential' | 'inpatient_unit';
  agreement_id?: string;         // UUID — if agreement already created at admission
  resident_agreement?: {
    agreement_id: string;
    payment_terms: {
      amount: number;
      frequency: 'weekly' | 'bi_weekly' | 'monthly';
      start_date: string;
      due_day_of_month?: number;
      payment_methods: ('check' | 'ach' | 'card' | 'cash')[];
      late_fee_amount?: number;
      grace_period_days?: number;
    };
  };
}
```

**Purpose:** FA Core creates billing account and sets up recurring invoice schedule. PM uses `facility_type` to derive POS for charge capture (PM-07). `user_id` captures the staff member who performed the admission for audit and accountability.

**Consumer implementation note:** FA should follow the `fa-consume-pm-payment-events` batch pattern (read `fw_domain_events`, idempotency log per event id) — dedicated `fa-consume-rh-episode-events` function 📋 Planned until FA episode AR schema is finalized.

***

### RH-01: Resident Discharge Events

**Event (canonical):** `rh_resident_discharged`\
**Deprecated alias:** `resident_discharged`
**Publisher:** RH (Recovery Housing)
**Subscribers:** FA (Finance & Revenue), PM (census/bed-day billing finalization)
**Persistence:** `fw_domain_events` (trigger on `rh_episodes`)
**Status:** 🟡 Implemented (DB persistence); FA/PM batch consumers 📋 Planned
**Spec Reference:** [RH-01 Census, Beds & Episodes](../../../specs/rh/specs/RH-01-census-beds-episodes.md) · [RH-01.1 Bed Board & Facility Types](../../../specs/rh/specs/RH-01.1-bed-board-facility-types.md)
**Integration Doc:** [RH-01-bed-board-census-INTEGRATION.md](./bed-board-census-integration.md)

**Payload Schema:**

```typescript theme={null}
{
  event_name: 'rh_resident_discharged';
  timestamp: string;             // ISO 8601 / timestamptz
  organization_id: string;
  site_id?: string;
  correlation_id?: string;
  episode_id: string;
  resident_profile_id: string;
  residence_id: string;
  discharge_date: string;
  user_id: string;               // UUID — staff member who performed the discharge (audit/accountability)
  discharge_type: 'planned' | 'ama' | 'non_compliance' | 'completion' | 'extension';
  facility_type: 'recovery_housing' | 'psychiatric_residential' | 'inpatient_unit';
  actual_length_of_stay_days: number;
  exit_destination?: string;
  final_balance?: {
    outstanding_balance: number;
    last_payment_date?: string;
    last_payment_amount?: number;
  };
}
```

**Purpose:** FA Core finalizes billing and closes billing account. PM uses `facility_type` and `actual_length_of_stay_days` for bed-day billing reconciliation. `user_id` captures the staff member who performed the discharge for audit and accountability.

***

### RH-01: Bed Assignment Events

**Event (target canonical):** `rh_bed_assigned`\
**Deprecated alias:** `bed_assigned`\
**Publisher:** RH (Recovery Housing)
**Subscribers:** HR (workload/census update)
**Persistence:** ✅ Now in `KnownEventName` — trigger when HR consumer is scheduled
**Status:** 📝 Planned (RH-01.1 Implementation)
**Spec Reference:** [RH-01.1 Bed Board & Facility Types](../../../specs/rh/specs/RH-01.1-bed-board-facility-types.md)
**Integration Doc:** [RH-01-bed-board-census-INTEGRATION.md](./bed-board-census-integration.md)

**Payload Schema:**

```typescript theme={null}
{
  event_name: 'rh_bed_assigned';
  timestamp: string;             // ISO 8601 / timestamptz
  organization_id: string;
  site_id?: string;
  correlation_id?: string;
  episode_id: string;
  bed_id: string;
  residence_id: string;
  user_id: string;               // UUID — staff member who assigned the bed (audit/accountability)
  facility_type: 'recovery_housing' | 'psychiatric_residential' | 'inpatient_unit';
  unit_label?: string;   // Non-null for inpatient_unit
  assigned_at: string;
}
```

**Purpose:** HR updates workload/staffing census when a bed is assigned. `user_id` captures the staff member who performed the assignment for audit and accountability.

***

### RH-01: Bed Released Events

**Event (target canonical):** `rh_bed_released`\
**Deprecated alias:** `bed_released`
**Publisher:** RH (Recovery Housing)
**Subscribers:** HR (workload/census update)
**Persistence:** ✅ Now in `KnownEventName`
**Status:** 📝 Planned (RH-01.1 Implementation)
**Spec Reference:** [RH-01.1 Bed Board & Facility Types](../../../specs/rh/specs/RH-01.1-bed-board-facility-types.md)
**Integration Doc:** [RH-01-bed-board-census-INTEGRATION.md](./bed-board-census-integration.md)

**Payload Schema:**

```typescript theme={null}
{
  event_name: 'rh_bed_released';
  timestamp: string;             // ISO 8601 / timestamptz
  organization_id: string;
  site_id?: string;
  correlation_id?: string;
  episode_id: string;
  bed_id: string;
  residence_id: string;
  user_id: string;               // UUID — staff member who released the bed (audit/accountability)
  facility_type: 'recovery_housing' | 'psychiatric_residential' | 'inpatient_unit';
  released_at: string;
}
```

**Purpose:** HR updates workload/staffing census when a bed is released after discharge. `user_id` captures the staff member who performed the release for audit and accountability.

***

### RH-01: Invoice Creation Requested Events

**Event (canonical):** `rh_invoice_creation_requested`\
**Legacy alias (deprecated):** `invoice_creation_requested` — maintained for backward compatibility but should migrate to canonical name\
**Publisher:** RH (Recovery Housing)
**Subscribers:** FA (Finance & Revenue)
**Channel:** `rh_events`
**Status:** 📝 Planned (RH-01 Implementation)
**Spec Reference:** [RH-01 Census, Beds & Episodes](../../../specs/rh/specs/RH-01-census-beds-episodes.md)
**Integration Doc:** [RH-01-bed-board-census-INTEGRATION.md](./bed-board-census-integration.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'rh_invoice_creation_requested'; // Canonical name; legacy 'invoice_creation_requested' deprecated
  timestamp: string;             // ISO 8601 / timestamptz
  organization_id: string;
  site_id?: string;
  correlation_id?: string;
  episode_id: string;
  resident_profile_id: string;
  residence_id: string;
  agreement_id: string;
  user_id?: string;              // UUID — present when a staff member manually triggers invoice creation; omitted when auto-generated by the billing schedule
  payment_amount: number;
  payment_frequency: 'weekly' | 'bi_weekly' | 'monthly';
  payment_start_date: string;
  due_day_of_month?: number;
  payment_methods: string[];
  late_fee_amount: number;
  grace_period_days: number;
  admission_date: string;
  facility_type: 'recovery_housing' | 'psychiatric_residential' | 'inpatient_unit';
}
```

**Purpose:** FA creates the first invoice based on the resident agreement payment terms. `facility_type` helps FA tag invoices by service line for financial reporting. `user_id` is present when a staff member manually triggers invoice creation; omitted when auto-generated by the billing schedule.

***

### RH-03: Critical Incident Events

**Event 1 (canonical):** `rh_critical_significant_event_reported`\
**Legacy alias (deprecated):** `critical_significant_event_reported`\
**Publisher:** RH (RH-03 Safety Events & Compliance)\
**Subscribers:** PF-10 (notifications)\
**Channel:** `rh_events`\
**Status:** 📝 Planned\
**Spec Reference:** [RH-03 Safety Events & Compliance](../../../specs/rh/specs/RH-03-safety-events-compliance.md)\
**Integration Doc:** [RH-03-safety-events-compliance-INTEGRATION.md](./safety-events-compliance-integration.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'rh_critical_significant_event_reported';
  significant_event_id: uuid;
  organization_id: uuid;
  episode_id: uuid;
  severity: 'critical';
  occurred_at: timestamptz;
  correlation_id?: uuid;
}
```

**Event 2 (canonical):** `rh_significant_event_investigation_completed`\
**Legacy alias (deprecated):** `significant_event_investigation_completed`\
**Publisher:** RH (RH-03 Safety Events & Compliance)\
**Subscribers:** PF-10, RH compliance/reporting consumers\
**Channel:** `rh_events`\
**Status:** 📝 Planned\
**Spec Reference:** [RH-03 Safety Events & Compliance](../../../specs/rh/specs/RH-03-safety-events-compliance.md)\
**Integration Doc:** [RH-03-safety-events-compliance-INTEGRATION.md](./safety-events-compliance-integration.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'rh_significant_event_investigation_completed';
  significant_event_id: uuid;
  investigation_id: uuid;
  organization_id: uuid;
  completed_at: timestamptz;
  correlation_id?: uuid;
}
```

**Event 3 (canonical):** `rh_uds_test_positive`\
**Legacy alias (deprecated):** `uds_test_positive`\
**Publisher:** RH (RH-03 Safety Events & Compliance)\
**Subscribers:** RH-03 relapse/event workflows, PF-10 notifications\
**Channel:** `rh_events`\
**Status:** 📝 Planned\
**Spec Reference:** [RH-03 Safety Events & Compliance](../../../specs/rh/specs/RH-03-safety-events-compliance.md)\
**Integration Doc:** [RH-03-safety-events-compliance-INTEGRATION.md](./safety-events-compliance-integration.md)

**Payload Schema (consent-safe identifier-only):**

```typescript theme={null}
{
  event_type: 'rh_uds_test_positive';
  uds_test_id: uuid;
  organization_id: uuid;
  episode_id: uuid;
  tested_at: timestamptz;
  correlation_id?: uuid;
}
```

**Part 2 / consent handling:** Subscribers MUST NOT expect `substances` or narrative test detail in this payload. Consumers must perform an RH-controlled, consent-gated read (RH-04 EN-4) before retrieving UDS result details.

***

### RH-04: Resident Billing Events

**Event:** `resident_charge_created`\
**Publisher:** RH (Recovery Housing)\
**Subscribers:** FA-05 (Accounts Receivable)\
**Status:** 📝 Planned (RH-04 Implementation)\
**Spec Reference:** [FA-05: Accounts Receivable & Revenue Recognition](../../../specs/fa/specs/FA-05-accounts-receivable.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'resident_charge_created';
  resident_id: uuid;
  charge_id: uuid;
  charge_date: date;
  amount: number;
  description: string;
  account_id: uuid;  // Revenue account
  organization_id: uuid;
  site_id: uuid;
  user_id: uuid;  // ID of the user who created the charge (for audit trail)
  timestamp: timestamptz;
}
```

**Purpose:** FA-05 auto-generates invoices from resident charges. When RH-04 publishes this event, FA-05 creates an invoice for the resident's linked customer record, posts it to GL, and links the invoice to the source charge for traceability.

**Consumer Actions:**

1. FA-05 looks up resident → customer mapping
2. Creates invoice with charge as line item
3. Sets invoice status to "sent" and auto-posts to GL (DR AR, CR Revenue)
4. Links invoice to source charge via `fa_invoices.source_charge_id`
5. Sends notification to billing coordinator (PF-10)

**Implementation Notes:**

* Event contract defined in FA-05 spec (Section 9: Integration Points)
* Database schema ready: `fa_invoices.source_charge_id` column exists
* Event consumer implementation pending RH-04 completion
* Batch processing support for 100+ charges/day
* **CRITICAL:** The database trigger that emits this event MUST capture the creating user's ID from the session/context (e.g., using `auth.uid()` or `current_setting('request.jwt.claims', true)::json->>'sub'`) and populate the `user_id` field in the emitted event payload. This ensures the audit trail is preserved and traceable to the specific user who created the charge.

***

### RH-06: Compliance Events

**Event 1:** `compliance_deadline_approaching`\
**Publisher:** RH (Recovery Housing)\
**Subscribers:** PF-10 (Notifications)\
**Status:** 📝 Planned\
**Spec Reference:** RH-06 (Compliance Tracking & Staff Operations)

**Payload Schema:**

```typescript theme={null}
{
  compliance_requirement_id: uuid;
  organization_id: uuid;
  due_date: date;
  days_until_due: number;
}
```

**Purpose:** Send compliance deadline reminders 7 days before due date

**Event 2:** `non_compliance_detected`\
**Publisher:** RH (Recovery Housing)\
**Subscribers:** PF-10 (Notifications)\
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
{
  compliance_requirement_id: uuid;
  organization_id: uuid;
  residence_id?: uuid;
  non_compliance_reason: string;
}
```

**Purpose:** Alert management to non-compliance issues

***

### FA-01: Payment Received Events

**Event:** `payment_received`\
**Publisher:** FA (Finance & Revenue)\
**Subscribers:** RH (Recovery Housing)\
**Status:** 📝 Planned (FA-01 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'payment_received';
  event_timestamp: timestamp;
  organization_id: uuid;
  episode_id: uuid;
  payment_id: uuid;
  payment_amount: number;
  payment_method: 'cash' | 'check' | 'card' | 'ach' | 'other';
  payment_date: date;
  new_balance: number;
  payment_status: 'current' | 'past_due' | 'paid_in_full';
}
```

**Purpose:** RH Core updates cached payment status based on received payments

***

### HR-01: Employee Assignment Events

**Event:** `employee_assigned_to_site`
**Publisher:** HR (Workforce)
**Subscribers:** RH (Recovery Housing)
**Channel:** `hr_events`
**Status:** 📝 Planned (RH-06 Implementation, Q2 2026)

**Payload Schema:**

```typescript theme={null}
{
  employee_id: uuid;
  site_id: uuid;
  organization_id: uuid;
  assignment_date: timestamp;
  role: 'staff' | 'manager' | 'admin';
  department_id?: uuid;
}
```

**Purpose:** RH Core receives notifications when staff are assigned to recovery housing sites

***

### HR-01: Employee Created Events

**Event:** `employee_created`
**Publisher:** HR (Workforce)
**Subscribers:** GR (Governance & Risk)
**Channel:** `hr_events`
**Status:** 📝 Planned (Q2 2026)

**Payload Schema:**

```typescript theme={null}
{
  employee_id: uuid;
  organization_id: uuid;
  department_id?: uuid;
  position_id?: uuid;
  hire_date: timestamp;
  is_clinical: boolean;
}
```

**Purpose:** GR Core assigns default policies and training requirements to new employees

***

### LO-01: Vision & Strategic Planning Events (Planned)

**Event:** `vision_updated`\
**Status:** 📝 Planned (LO-01 Implementation)

**Event:** `strategic_goal_created`\
**Status:** 📝 Planned (LO-01 Implementation)

**Event:** `rock_created`\
**Status:** 📝 Planned (LO-01 Implementation)

***

### LO-02: Accountability Chart Events (Planned)

**Event:** `role_assigned`\
**Status:** 📝 Planned (LO-02 Implementation)

**Event:** `accountability_chart_updated`\
**Status:** 📝 Planned (LO-02 Implementation)

***

### LO-08: Feedback & 1-on-1s Events (Planned)

**Event:** `one_on_one_scheduled`\
**Status:** 📝 Planned (LO-08 Implementation)

**Event:** `feedback_submitted`\
**Status:** 📝 Planned (LO-08 Implementation)

***

### LO-10: Knowledge Portal Events (Planned)

**Event:** `knowledge_article_created`\
**Status:** 📝 Planned (LO-10 Implementation)

**Event:** `process_updated`\
**Status:** 📝 Planned (LO-10 Implementation)

***

### LO-16: Goals & Actions Event Integration (Planned)

**Event:** `goal_created`\
**Publisher:** LO (Leadership Operating System)\
**Subscribers:** FA (budget planning), GR (compliance), FW (workflow linking)\
**Status:** 📝 Planned (LO-16 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'goal_created';
  payload: {
    goal_id: uuid;
    goal_title: string;
    goal_quarter: string;
    goal_fiscal_year: number;
    organization_id: uuid;
    site_id?: uuid;
    created_by: uuid;
    executive_sponsor_id?: uuid;
    strategic_goal_id?: uuid;
    created_at: timestamptz;
  };
  timestamp: timestamptz;
}
```

**Event:** `goal_completed`\
**Publisher:** LO\
**Subscribers:** RH (program metrics), FA (financial tracking), GR (compliance tracking)\
**Status:** 📝 Planned (LO-16 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'goal_completed';
  payload: {
    goal_id: uuid;
    goal_title: string;
    goal_quarter: string;
    organization_id: uuid;
    completed_by: uuid;
    completed_at: timestamptz;
    progress_percentage: number;
    smart_score?: number;
  };
  timestamp: timestamptz;
}
```

**Event:** `action_assigned`\
**Publisher:** LO\
**Subscribers:** HR (employee development), PF-10 (notifications)\
**Status:** 📝 Planned (LO-16 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'action_assigned';
  payload: {
    action_id: uuid;
    goal_id: uuid;
    action_title: string;
    organization_id: uuid;
    assigned_to: uuid;
    assigned_by: uuid;
    assigned_at: timestamptz;
  };
  timestamp: timestamptz;
}
```

**Event:** `action_completed`\
**Publisher:** LO\
**Subscribers:** LO-14 (unblock dependencies), PF-10 (notifications)\
**Status:** 📝 Planned (LO-16 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'action_completed';
  payload: {
    action_id: uuid;
    goal_id: uuid;
    action_title: string;
    organization_id: uuid;
    completed_by: uuid;
    completed_at: timestamptz;
    actual_hours?: number;
  };
  timestamp: timestamptz;
}
```

**Implementation:**

* Events published via `lo_events` channel (pg\_notify)
* Database triggers on `lo_quarterly_rocks` and `lo_rock_milestones`
* Events logged to `pf_audit_logs` for audit trail
* Consumer examples provided for RH, FA, GR, FW modules

**Related Spec:** `specs/lo/LO-16-goals-event-integration.md`

***

## Planned Events (GR Core)

### GR-01: Policy Management Events

**Event 1:** `policy_created`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-02 (Training assignments), GR-03 (Compliance evidence)\
**Status:** 📝 Planned (GR-01 Implementation)\
**Spec Reference:** [GR-01 Policy Management](../../../specs/gr/specs/GR-01-policy-management.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'policy_created';
  policy_id: uuid;
  organization_id: uuid;
  site_id?: uuid;
  title: string;
  category: string;
  status: 'draft' | 'review' | 'approved';
  effective_date: date;
  created_by: uuid;
  timestamp: timestamptz;
}
```

**Event 2:** `policy_acknowledged`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-02 (Training compliance), GR-03 (Compliance tracking)\
**Status:** 📝 Planned (GR-01 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'policy_acknowledged';
  acknowledgment_id: uuid;
  policy_id: uuid;
  employee_id: uuid;
  organization_id: uuid;
  acknowledged_at: timestamptz;
  policy_version: string;
  timestamp: timestamptz;
}
```

***

### GR-02: Training & CEU Tracking Events

**Event:** `training_completed`
**Publisher:** GR (Governance & Compliance)
**Subscribers:** GR-03 (Compliance evidence), HR-02 (Credentialing)
**Status:** ✅ Implemented (GR-02-EN-01, 2026-05-01)
**Spec Reference:** [GR-02 Training & CEU Tracking](../../../specs/gr/specs/GR-02-training-ceu-tracking.md)

**Channel / Transport:** `gr_events` (`pg_notify`) **+ direct HTTP fan-out via `pg_net`** (see "Delivery bridge" below)
**Trigger:** `gr_on_training_completed` (AFTER INSERT on `gr_training_completions`) → `public.gr_publish_training_completed()` (SECURITY DEFINER)
**Consumers (HTTP):**

* `hr-training-credential-refresh` — recomputes `ce_hours_completed` on employee credentials
* `gr-evidence-from-training` — inserts deduplicated `gr_compliance_evidence` rows for linked requirements

**Delivery bridge (2026-05-01):** After publishing to `pg_notify('gr_events', ...)` the trigger calls `public.gr_dispatch_training_event('training_completed', payload)` (SECURITY DEFINER, `service_role`-only EXECUTE). The dispatcher reads `project_url` and `service_role_key` from `vault.decrypted_secrets` and issues two `net.http_post` calls — one to `/functions/v1/gr-evidence-from-training` and one to `/functions/v1/hr-training-credential-refresh` — with `X-Correlation-Id` propagated from the publisher's correlation ID. Each HTTP call is wrapped in its own `BEGIN…EXCEPTION` block and any failure is logged with `RAISE WARNING` so dispatcher errors never block the originating INSERT. The `pg_notify` channel is preserved for back-compat and unit-test contracts. Migration: `supabase/migrations/20260501114741_*.sql`.

**Idempotency:** Consumers rely on partial unique index `gr_compliance_evidence_org_req_src_uq` on `(organization_id, requirement_id, source_reference)` so retried deliveries are safe.

**PHI/PII:** Payload contains identifiers and aggregate CEU credit only — no patient data, no employee names, no certificate content.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'training_completed';
  enrollment_id: uuid;
  course_id: uuid;
  employee_profile_id: uuid;
  organization_id: uuid;
  completion_date: date;
  ceu_credits: number;
  certificate_issued: boolean;
  // Linkage resolved by the publisher trigger from gr_training_requirement_links
  // and gr_training_policy_links (arrays may be empty, never null)
  requirement_ids: uuid[];
  policy_ids: uuid[];
  timestamp: timestamptz;
}
```

***

**Event:** `enrollment_overdue`
**Publisher:** GR (Governance & Compliance)
**Subscribers:** GR-03 (Compliance evidence / status), HR-02 (Credentialing risk), PF notifications
**Status:** ✅ Implemented (GR-02-EN-01, 2026-05-01)
**Spec Reference:** [GR-02-EN-01 Training Events](../../../specs/gr/specs/GR-02-EN-01-training-events.md)

**Channel / Transport:** `gr_events` (`pg_notify`) **+ HTTP dispatcher placeholder via `pg_net`**
**Trigger:** `gr_on_enrollment_overdue` (BEFORE UPDATE on `gr_training_enrollments`) → `public.gr_publish_enrollment_overdue()` (SECURITY DEFINER)

**Delivery bridge (2026-05-01):** Trigger also calls `public.gr_dispatch_training_event('enrollment_overdue', payload)`. No HTTP consumer is wired yet — the dispatcher currently emits a `RAISE NOTICE` placeholder. Follow-up work will fan out to a notification / supervisor-escalation edge function.

**Idempotency:** The trigger fires only on transitions where `NEW.status = 'overdue'` AND `OLD.status IS DISTINCT FROM 'overdue'` AND `overdue_event_published_at IS NULL`. The trigger sets `overdue_event_published_at = now()` in the same row update, guaranteeing at most one publication per enrollment per overdue cycle.

**PHI/PII:** Identifiers and due-date metadata only — no employee name or course content.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'enrollment_overdue';
  enrollment_id: uuid;
  course_id: uuid;
  employee_profile_id: uuid;
  organization_id: uuid;
  due_date: date;
  days_overdue: number;        // computed at publish time (>= 0)
  previous_status: string;     // OLD.status, e.g. 'in_progress' | 'not_started'
  timestamp: timestamptz;
}
```

**Audit:** Both publishers best-effort insert into `pf_audit_logs` with a generated correlation ID (failures swallowed so trigger does not block the originating write).

#### GR-02-EN-04 (PF-96 → CE requirement library)

**Event Name:** Consumes `pf_jurisdiction_profile_changed` from PF-96; **no new emitted event**

**Publisher:** PF-96 (Jurisdiction Profiles)

**Subscribers:** GR-02 training requirement catalog service

**Status:** 📝 Planned

**Spec Reference:** [GR-02-EN-04](../../../specs/gr/specs/GR-02-EN-04-pf-96-ce-requirement-library.md)

**Purpose:** GR-02 training requirement catalogs consume PF-96 jurisdiction profile metadata to align with CE-facing requirement libraries. No new cross-core event is emitted; GR-02 subscribes to the existing `pf_jurisdiction_profile_changed` event.

**Payload Schema (consumed from PF-96):**

```typescript theme={null}
{
  event_type: 'pf_jurisdiction_profile_changed';
  jurisdiction_id: uuid;
  jurisdiction_code: string;
  organization_id: uuid;
  profile_data: {
    training_requirements?: {
      required_hours?: number;
      renewal_period?: string;
      specialty_requirements?: Record<string, unknown>;
    };
    // Additional jurisdiction-specific profile fields
  };
  changed_at: timestamptz;
  timestamp: timestamptz;
}
```

**Implementation Location:** GR-02 training requirement catalog service (event subscriber logic)

***

### GR-03: Compliance Tracking Events

**Event 1:** `requirement_created`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-04 (Audit checklists), GR-06 (AI assistance)\
**Status:** 📝 Planned (GR-03 Implementation)\
**Spec Reference:** [GR-03 Compliance Tracking](../../../specs/gr/specs/GR-03-compliance-tracking.md)

**Event 2:** `compliance_status_changed`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-04 (Audit readiness), GR-05 (Risk assessment), GR-06 (AI monitoring)\
**Status:** 📝 Planned (GR-03 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'compliance_status_changed';
  check_id: uuid;
  requirement_id: uuid;
  organization_id: uuid;
  old_status: 'compliant' | 'non_compliant' | 'pending';
  new_status: 'compliant' | 'non_compliant' | 'pending';
  changed_at: timestamptz;
  timestamp: timestamptz;
}
```

***

### GR-04: Audit Management Events

**Event 1:** `audit_created`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-06 (AI assistance)\
**Status:** 📝 Planned (GR-04 Implementation)\
**Spec Reference:** [GR-04 Audit Management](../../../specs/gr/specs/GR-04-audit-management.md)

**Event 2:** `audit_finding_created`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-05 (Risk assessment), GR-06 (AI monitoring)\
**Status:** 📝 Planned (GR-04 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'audit_finding_created';
  finding_id: uuid;
  audit_id: uuid;
  organization_id: uuid;
  severity: 'low' | 'medium' | 'high' | 'critical';
  finding_type: string;
  created_at: timestamptz;
  timestamp: timestamptz;
}
```

***

### GR-05: Risk Assessment Events

**Event 1:** `risk_created`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-06 (AI assistance)\
**Status:** 📝 Planned (GR-05 Implementation)\
**Spec Reference:** [GR-05 Risk Assessment](../../../specs/gr/specs/GR-05-risk-assessment.md)

**Event 2:** `risk_assessed`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-06 (AI monitoring)\
**Status:** 📝 Planned (GR-05 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'risk_assessed';
  risk_id: uuid;
  organization_id: uuid;
  risk_score: number;
  risk_level: 'low' | 'medium' | 'high' | 'critical';
  assessed_at: timestamptz;
  timestamp: timestamptz;
}
```

***

### GR-11: Procedures Management Events

**Event 1:** `procedure_approved`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-02 (Training), GR-03 (Compliance)\
**Status:** ✅ Complete (GR-11 Implementation)\
**Spec Reference:** [GR-11 Procedures Management](../../../specs/gr/specs/GR-11-procedures-management.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'procedure_approved';
  procedure_id: uuid;
  organization_id: uuid;
  site_id?: uuid;          // Site scope if applicable
  user_id: uuid;           // User who approved
  title: string;
  category: string;
  implements_policy_id: uuid | null;
  approved_by: uuid;
  approved_at: timestamptz;
  correlation_id: string | null;
  timestamp: timestamptz;
}
```

**Purpose:** Notify when procedure is approved for use, enabling training assignments and compliance tracking

**Consumer Actions:**

| Consumer              | Action                                         | Status     |
| --------------------- | ---------------------------------------------- | ---------- |
| GR-02 (Training)      | Create training assignment for new procedure   | 📝 Planned |
| GR-03 (Compliance)    | Update compliance tracking for policy coverage | 📝 Planned |
| PF-10 (Notifications) | Notify procedure owner and stakeholders        | 📝 Planned |

**Testing Requirements:**

* [ ] Event fires when procedure status changes to 'approved'
* [ ] Payload includes all required fields including site\_id
* [ ] Event logged to pf\_audit\_logs
* [ ] Tenant isolation verified (org\_id matches)

***

**Event 2:** `procedure_execution_completed`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-03 (Compliance evidence)\
**Status:** ✅ Complete (GR-11 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'procedure_execution_completed';
  execution_id: uuid;
  procedure_id: uuid;
  organization_id: uuid;
  site_id?: uuid;          // Site scope if applicable
  user_id: uuid;           // Mirrors executed_by for consistency
  executed_by: uuid;
  completed_at: timestamptz;
  context_type: string | null;
  context_id: uuid | null;
  correlation_id: string | null;
  timestamp: timestamptz;
}
```

**Purpose:** Provide compliance evidence of procedure execution

**Consumer Actions:**

| Consumer              | Action                                  | Status     |
| --------------------- | --------------------------------------- | ---------- |
| GR-03 (Compliance)    | Record execution as compliance evidence | 📝 Planned |
| PF-10 (Notifications) | Notify procedure owner of completion    | 📝 Planned |

**Testing Requirements:**

* [ ] Event fires when execution status changes to 'completed'
* [ ] Payload includes procedure and execution context
* [ ] Event logged to pf\_audit\_logs
* [ ] Related entity (context\_type/context\_id) included when available

***

**Implementation:**

* Events published via `gr_events` channel (pg\_notify)
* Database triggers on `gr_procedures` (status change to 'approved') and `gr_procedure_executions` (status change to 'completed')
* Events logged to `pf_audit_logs` for audit trail with `user_id` and `correlation_id` fields populated
* Consumer examples provided for GR-02, GR-03 modules

**Trigger Function Requirements:**

* **All trigger functions that publish events to the `gr_events` channel MUST be created WITH SECURITY DEFINER**
* **Coding Guideline:** SQL trigger code for events must include `SECURITY DEFINER` clause
* The trigger function owner and privileges must be set appropriately so the function can emit notifications even when invoked by less-privileged roles to remain compliant
* Trigger functions must populate `user_id` from the current session context (e.g., `auth.uid()`) in addition to any role-specific fields like `approved_by` or `executed_by`
* When events may chain (e.g., procedure approval triggers training assignment), trigger functions should generate and propagate `correlation_id` to enable event traceability

***

### GR-06-EN-01: AI-Powered State Compliance Checking Events

**Event:** `gr_state_gap_analysis_completed`\
**Publisher:** GR-06-EN-01 (Governance & Compliance)\
**Subscribers:** PF-91 (compliance dashboard), PF-10 (notifications — critical gap alerts)\
**Channel / Transport:** `gr_events` (`pg_notify`) — **planned** (align with other GR event publications); Kafka topic **TBD** if/when event bus externalizes\
**Status:** 📝 Planned (Phase 4 — emit when state gap analysis completes)\
**Contract version:** 1.0 (draft)\
**Spec / integration:** [GR-06-EN-01](../../../specs/gr/specs/GR-06-EN-01-ai-state-compliance-checking.md) · [Integration](./ai-state-compliance-checking-integration.md)

**Payload schema (JSON fields):**

| Field              | Type              | Required | Description                                                             |
| ------------------ | ----------------- | -------- | ----------------------------------------------------------------------- |
| `event_type`       | string            | yes      | Literal `gr_state_gap_analysis_completed`                               |
| `event_id`         | uuid              | yes      | Unique event ID for deduplication                                       |
| `organization_id`  | uuid              | yes      | Tenant scope                                                            |
| `state_code`       | string            | yes      | Jurisdiction state code (e.g. `AZ`)                                     |
| `domain`           | string            | yes      | One of `clinical`, `billing`, `compliance`, `training`, `comprehensive` |
| `compliance_score` | number            | yes      | 0–100                                                                   |
| `gap_count`        | integer           | yes      | Count of identified gaps                                                |
| `timestamp`        | string (ISO 8601) | yes      | Event time (`timestamptz`)                                              |
| `correlation_id`   | string \| null    | no       | Trace / workflow correlation                                            |

```typescript theme={null}
interface GrStateGapAnalysisCompletedPayload {
  event_type: 'gr_state_gap_analysis_completed';
  event_id: string; // UUID — canonical deduplication key
  organization_id: string; // UUID
  state_code: string;
  domain: 'clinical' | 'billing' | 'compliance' | 'training' | 'comprehensive';
  compliance_score: number; // 0–100
  gap_count: number;
  timestamp: string; // ISO 8601 timestamptz
  correlation_id?: string | null;
}
```

**Consumer actions:**

| Consumer | Action                                               | Status     |
| -------- | ---------------------------------------------------- | ---------- |
| PF-91    | Refresh compliance dashboard widgets / gap summaries | 📝 Planned |
| PF-10    | Notify compliance roles when gaps are critical       | 📝 Planned |

***

### GR-12: Procedure Templates Library Events

**Event 1:** `gr_template_instantiated`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-03 (Compliance tracking), PF-10 (optional notification)\
**Status:** 📝 Planned (GR-12 Implementation)\
**Spec Reference:** [GR-12 Procedure Templates Library](../../../specs/gr/specs/GR-12-procedure-templates-library.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'gr_template_instantiated';
  template_id: uuid;
  procedure_id: uuid;          // newly created procedure
  organization_id: uuid;
  user_id: uuid;
  timestamp: timestamptz;
  correlation_id: string | null;
}
```

**Purpose:** Notify when a template is instantiated as a new procedure, enabling compliance tracking updates.

**Consumer Actions:**

| Consumer              | Action                                                   | Status     |
| --------------------- | -------------------------------------------------------- | ---------- |
| GR-03 (Compliance)    | Update compliance coverage tracking                      | 📝 Planned |
| PF-10 (Notifications) | Notify compliance officer of new procedure from template | 📝 Planned |

***

**Event 2:** `gr_template_contributed`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-03 (Compliance tracking)\
**Status:** 📝 Planned (GR-12 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'gr_template_contributed';
  template_id: uuid;
  source_procedure_id: uuid;
  organization_id: uuid;
  user_id: uuid;
  timestamp: timestamptz;
  correlation_id: string | null;
}
```

**Purpose:** Notify when an approved procedure is contributed as an org-private template.

***

### GR-07: Quality Improvement Events

**Event:** `qi_project_created`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-03 (Compliance tracking), GR-04 (Audit management)\
**Status:** 📝 Planned (GR-07 Implementation)\
**Spec Reference:** [GR-07 Quality Improvement](../../../specs/gr/specs/GR-07-quality-improvement.md)

***

### GR-08: Accreditation Management Events

**Event:** `accreditation_created`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-03 (Compliance tracking), GR-04 (Audit management)\
**Status:** 📝 Planned (GR-08 Implementation)\
**Spec Reference:** [GR-08 Accreditation Management](../../../specs/gr/specs/GR-08-accreditation-management.md)

***

### GR-15: Nonprofit Governance Controls Events

**Status:** ✅ Implemented\
**Implemented:** 2026-03-12 (PR #1002 remediation)\
**Spec Reference:** [GR-15 Nonprofit Governance Controls](../../../specs/gr/specs/GR-15-nonprofit-governance-controls.md)

#### Event 1: `gr_coi_cycle_launched`

**Publisher:** GR (Governance & Compliance)\
**Subscribers:** PF-10 (Notifications — reminder emails to attestation participants), GR-03 (Compliance tracking — annual COI completion)\
**Channel:** `gr_events`\
**Status:** ✅ Implemented

**Payload Schema:**

```typescript theme={null}
interface GrCoiCycleLaunchedPayload {
  event_type: 'gr_coi_cycle_launched';
  organization_id: string;    // UUID
  cycle_id: string;           // UUID — gr_coi_cycles record
  cycle_year: number;         // e.g. 2026
  due_date: string;           // ISO date — attestation deadline
  participant_count: number;  // Number of employees included
  launched_by: string;        // UUID — user who initiated
  timestamp: string;          // ISO 8601 timestamptz
  correlation_id?: string;    // UUID
}
```

#### Event 2: `gr_whistleblower_report_submitted`

**Publisher:** GR (Edge function: `gr-whistleblower-submit`)\
**Subscribers:** PF-10 (Notifications — alert compliance officers), GR-03 (Compliance tracking)\
**Channel:** `gr_events`\
**Status:** ✅ Implemented

**Payload Schema:**

```typescript theme={null}
interface GrWhistleblowerReportSubmittedPayload {
  event_type: 'gr_whistleblower_report_submitted';
  organization_id: string;    // UUID
  report_id: string;          // UUID — gr_whistleblower_reports record
  category: string;           // e.g. 'financial', 'safety', 'compliance', 'other'
  is_anonymous: boolean;      // Whether submitter opted for anonymity
  timestamp: string;          // ISO 8601 timestamptz
  // NOTE: No PII fields — reporter identity is never included in event payload
}
```

***

### CL-07-EN-01: Zero Suicide Framework Events

**Event 1:** `cl_safety_plan_shared`\
**Channel:** `cl_events`\
**Publisher:** CL (CL-07-EN-01 Zero Suicide Framework)\
**Subscribers:** PF-10 (Notifications — notify shared contacts), workflow listeners\
**Status:** 📝 Planned\
**PHI Restrictions:** UUIDs only (safety\_plan\_id, patient\_id). No patient names, DOB, SSN, or clinical detail.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'cl_safety_plan_shared';
  organization_id: uuid;
  timestamp: timestamptz;
  patient_id: uuid;
  safety_plan_id: uuid;
  shared_by: uuid;
  shared_at: timestamptz;
  correlation_id?: uuid;
}
```

| Consumer            | Action                                                                         | Status     |
| ------------------- | ------------------------------------------------------------------------------ | ---------- |
| PF-10 Notifications | Send notification to clinician/support network with signed URL in `action_url` | 📝 Planned |

***

**Event 2:** `cl_zero_suicide_followup_scheduled`\
**Channel:** `cl_events`\
**Publisher:** CL (CL-07-EN-01 Zero Suicide Framework)\
**Subscribers:** PM scheduling views, PF-10 (reminders)\
**Status:** 📝 Planned\
**PHI Restrictions:** UUIDs only (patient\_id, encounter\_id). No patient names, DOB, SSN, or clinical detail.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'cl_zero_suicide_followup_scheduled';
  organization_id: uuid;
  timestamp: timestamptz;
  patient_id: uuid;
  followup_type: string;       // '24h' | '48h' | '72h'
  scheduled_for: timestamptz;
  encounter_id?: uuid;
  correlation_id?: uuid;
}
```

| Consumer            | Action                                | Status     |
| ------------------- | ------------------------------------- | ---------- |
| PM Scheduling       | Display follow-up in scheduling views | 📝 Planned |
| PF-10 Notifications | Send reminder to assigned clinician   | 📝 Planned |

***

### CL–GR Bridge Events (Incident Bridge)

> **Contract Source:** Full event contract, payload schema, security requirements, and testing requirements are in [CL-GR-CLINICAL-INCIDENT-INTEGRATION.md](./CL-GR-CLINICAL-INCIDENT-INTEGRATION.md).\
> **Regulatory driver:** AHCCCS AMPM 1620-O; ARS 46-454; 42 CFR 482.13; CARF; Joint Commission EC.04.01.01.

**Event 1:** `cl_safety_plan_activated`\
**Channel:** `cl_events`\
**Publisher:** CL (CL-07 Suicide Risk Screening & Safety Planning)\
**Subscribers:** GR (GR-08/GR-09 Incident Reporting — creates draft incident)\
**Status:** 📝 Planned\
**PHI Restrictions:** UUIDs only (chart\_id, safety\_plan\_id, encounter\_id). No patient names, DOB, SSN, or clinical detail.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'cl_safety_plan_activated';
  organization_id: uuid;
  timestamp: timestamptz;
  site_id?: uuid;
  user_id?: uuid;
  chart_id: uuid;
  safety_plan_id?: uuid;
  encounter_id?: uuid;
  correlation_id?: uuid;
}
```

| Consumer    | Action                                                                                 | Status     |
| ----------- | -------------------------------------------------------------------------------------- | ---------- |
| GR-08/GR-09 | Create draft incident report; type = safety\_plan\_activation; link chart/safety\_plan | 📝 Planned |

***

**Event 2:** `cl_restraint_event_documented`\
**Channel:** `cl_events`\
**Publisher:** CL (CL-13 Crisis Intervention Documentation, when implemented)\
**Subscribers:** GR (GR-08/GR-09 — creates draft incident per 42 CFR 482.13)\
**Status:** 📝 Planned\
**PHI Restrictions:** UUIDs only. No patient names, DOB, SSN, or clinical detail.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'cl_restraint_event_documented';
  organization_id: uuid;
  timestamp: timestamptz;
  site_id?: uuid;
  user_id?: uuid;
  chart_id: uuid;
  encounter_id?: uuid;
  restraint_type: 'restraint' | 'seclusion';
  correlation_id?: uuid;
}
```

| Consumer    | Action                                                                          | Status     |
| ----------- | ------------------------------------------------------------------------------- | ---------- |
| GR-08/GR-09 | Create draft incident report; type = restraint\_seclusion; link chart/encounter | 📝 Planned |

***

**Event 3:** `gr_incident_created`\
**Channel:** `gr_events`\
**Publisher:** GR (GR-08/GR-09 Incident Reporting)\
**Subscribers:** CL (chart flag — open documentation requirement indicator)\
**Status:** ✅ Implemented\
**PHI Restrictions:** UUIDs only (chart\_id when patient-related). No patient names, DOB, SSN, or clinical detail.

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'gr_incident_created';
  organization_id: uuid;
  timestamp: timestamptz;
  site_id?: uuid;
  incident_id: uuid;
  chart_id?: uuid;          // when incident is patient-related
  incident_type?: string;
  correlation_id?: uuid;
}
```

| Consumer | Action                                                                                        | Status     |
| -------- | --------------------------------------------------------------------------------------------- | ---------- |
| CL       | Set chart-level flag "open documentation required" / "related incident"; link to incident\_id | 📝 Planned |

**Security and Resilience (all three bridge events):**

**Tenant Validation Requirements:**

1. **User-initiated flows:** Must validate `organization_id` against JWT claims (`current_setting('jwt.claims.organization_id')`) before any writes. Client-side checks are insufficient; server-side validation is mandatory.

2. **Service-initiated/pg\_notify flows:** Use a trusted organization context and MUST call a server-side `SECURITY DEFINER` stored procedure that:
   * Enforces strict `organization_id` checks against the trusted context
   * Includes auditable assertions (log mismatches to `pf_audit_logs`)
   * Rejects mismatches with explicit errors
   * Service-role callers must be limited to least-privilege roles
   * Includes audit logging for all event consumptions
   * Uses exponential backoff retries with dead-letter queue handling for max-retry failures

* All emissions and consumptions MUST be logged to `pf_audit_logs` with `user_id`, `organization_id`, `timestamp`, `correlation_id`.

***

### GR-09: Incident Reporting Events

**Event 1:** `incident_created`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-05 (Risk assessment), GR-06 (AI monitoring)\
**Status:** 📝 Planned (GR-09 Implementation)\
**Spec Reference:** [GR-09 Incident Reporting](../../../specs/gr/specs/GR-09-incident-reporting.md)

**Event 2:** `incident_resolved`\
**Publisher:** GR (Governance & Compliance)\
**Subscribers:** GR-05 (Risk update), GR-06 (AI monitoring)\
**Status:** 📝 Planned (GR-09 Implementation)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'incident_resolved';
  incident_id: uuid;
  organization_id: uuid;
  resolution_date: date;
  resolved_by: uuid;
  timestamp: timestamptz;
}
```

***

### GR-10 / GR-UX-10: Contract management & contract creation wizard

See [GR-10-contract-creation-INTEGRATION.md](./contract-creation-integration.md) for contract management and contract creation wizard integration details.

**Event Contract Template (GR-10):**

```yaml theme={null}
Event Name: None in v1
Publisher: None in v1
Subscribers: None in v1
Payload Schema: None in v1
Implementation Location: None in v1
```

**Status:** No events published in v1. Contract creation wizard (GR-UX-10) is local to GR core. Future integration candidates include FA (billing setup triggers) and workflow notifications.

**Spec Reference:** [GR-10 Contract Management](../../../specs/gr/specs/GR-10-contract-management.md), [GR-UX-10 Contract Creation Wizard](../../../specs/gr/ux/GR-UX-10-contract-creation-wizard.md)

***

### GR-13: Procedure Analytics Events

**Event 1:** `procedure_gap_identified`\
**Channel:** `gr_events`\
**Publisher:** GR (GR-13 Procedure Analytics)\
**Subscribers:** GR-07 (QI project candidate creation)\
**Status:** 📝 Planned\
**Spec Reference:** [GR-13 Procedure Analytics](../../../specs/gr/specs/GR-13-procedure-analytics.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'procedure_gap_identified';
  organization_id: uuid;
  procedure_id: uuid;
  procedure_title: string;
  category: string;
  completion_rate_pct: number;   // 0–100
  overdue_count: number;
  exported_by: uuid;             // user UUID
  exported_at: timestamptz;      // ISO 8601
  correlation_id?: uuid;
  timestamp: timestamptz;
}
```

| Consumer | Action                                                                                                                                                                                                                                                                                                                                         | Status                                                                                                                          |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| GR-07    | Create draft `gr_qi_projects` row with `status='draft'`, `source_event_id={fw_domain_events.id}`, `custom_fields.source_procedure_id={procedure_id}`; prefilled title / problem statement / suggested owner. Idempotent on `(organization_id, source_event_id)` + secondary guard on `(organization_id, source_procedure_id, status='draft')`. | ✅ Complete (consumer shipped in [GR-13-EN-01](../../../specs/gr/specs/GR-13-EN-01-gr-07-consumer-procedure-gap.md), 2026-04-19) |

**Purpose:** Notifies GR-07 that a procedure compliance gap was identified via analytics and a QI project should be considered.

**Implementation note (2026-04-19):** Publisher writes to `fw_domain_events` via `publishEvent()` (`src/platform/events/publishEvent.ts`). `fw_workflow_events` is the *registry* of event definitions, not the event log — the consumer subscribes to `fw_domain_events` rows where `event_name = 'procedure_gap_identified'`. The current payload does not include `gap_kind` / `metric` / `threshold_breached` (these were proposed in earlier drafts but never shipped); the consumer composes its initial problem statement from `procedure_title`, `completion_rate_pct`, and `overdue_count`.

***

## Event Infrastructure

**Generic Event Publisher:**

```sql theme={null}
CREATE FUNCTION publish_domain_event(_event_type TEXT, _payload JSONB)
RETURNS VOID AS $$
BEGIN
  PERFORM pg_notify('domain_events', json_build_object(
    'event_type', _event_type,
    'payload', _payload,
    'timestamp', now()
  )::text);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
```

**Event Consumer Edge Function:**

* Location: `supabase/functions/event-consumer/index.ts`
* Listens to `domain_events` channel
* Logs all events to `pf_audit_logs` with:
  * module = 'hr' (or relevant core)
  * action = 'domain\_event'
  * table\_name = source table
  * new\_values = event payload
* Future-ready for event handlers (commented code included)

**Testing:** ✅ Complete - All events logged correctly

***

## Planned Events (IT Module)

The IT (Information Technology) module defines 18 planned events for asset management, support ticketing, vendor management, software licensing, security compliance, and procurement.

**Full IT event documentation:** [IT Integration Contracts](./IT_INTEGRATION_CONTRACTS.md)

### IT-01: Asset Management Events

**Event 1:** `it_asset_purchased`\
**Publisher:** IT (IT-01 Asset Management)\
**Subscribers:** FA (Finance - asset capitalization)\
**Status:** ✅ Implemented\
**Last Verified:** 2026-02-15\
**Spec Reference:** [IT-01 IT Asset Management](../../../specs/it/specs/IT-01-it-asset-management.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'it_asset_purchased';
  asset_id: uuid;
  asset_tag: string;
  asset_type: string;
  asset_name: string;
  purchase_cost: number;
  purchase_date: date;
  vendor_id: uuid;
  organization_id: uuid;
  site_id?: uuid;
  timestamp: timestamptz;
}
```

**Implementation:**

```sql theme={null}
-- SECURITY DEFINER function definitions for IT asset triggers
CREATE OR REPLACE FUNCTION it_notify_asset_purchased()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
BEGIN
  PERFORM pg_notify('it_asset_purchased', json_build_object(
    'event_type', 'it_asset_purchased',
    'asset_id', NEW.id,
    'asset_tag', NEW.asset_tag,
    'asset_type', NEW.asset_type,
    'asset_name', NEW.name,
    'purchase_cost', NEW.purchase_cost,
    'purchase_date', NEW.purchase_date,
    'vendor_id', NEW.vendor_id,
    'organization_id', NEW.organization_id,
    'site_id', NEW.site_id,
    'timestamp', now()
  )::text);
  RETURN NEW;
END;
$$;

CREATE OR REPLACE FUNCTION it_notify_asset_disposed()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
BEGIN
  IF NEW.status = 'disposed' AND (OLD.status IS DISTINCT FROM 'disposed') THEN
    PERFORM pg_notify('it_asset_disposed', json_build_object(
      'event_type', 'it_asset_disposed',
      'asset_id', NEW.id,
      'asset_tag', NEW.asset_tag,
      'organization_id', NEW.organization_id,
      'timestamp', now()
    )::text);
  END IF;
  RETURN NEW;
END;
$$;

CREATE OR REPLACE FUNCTION it_notify_ticket_status_changed()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
BEGIN
  IF NEW.status IS DISTINCT FROM OLD.status THEN
    PERFORM pg_notify('it_ticket_status_changed', json_build_object(
      'event_type', 'it_ticket_status_changed',
      'ticket_id', NEW.id,
      'old_status', OLD.status,
      'new_status', NEW.status,
      'organization_id', NEW.organization_id,
      'timestamp', now()
    )::text);
  END IF;
  RETURN NEW;
END;
$$;

CREATE TRIGGER it_asset_purchased_trigger
  AFTER INSERT OR UPDATE ON it_assets
  FOR EACH ROW
  EXECUTE FUNCTION it_notify_asset_purchased();
```

**Event 2:** `it_asset_assigned`\
**Publisher:** IT (IT-01 Asset Management)\
**Subscribers:** PF-10 (Notifications), HR\
**Status:** ✅ Implemented

**Event 3:** `it_asset_maintenance_required`\
**Publisher:** IT (IT-01 Asset Management)\
**Subscribers:** FM (Facilities), PF-10 (Notifications)\
**Status:** 📝 Planned

**Event 4:** `it_asset_disposed`\
**Publisher:** IT (IT-01 Asset Management)\
**Subscribers:** FA (Finance), GR (Governance)\
**Status:** ✅ Implemented\
**Last Verified:** 2026-02-15

**Implementation:**

```sql theme={null}
CREATE TRIGGER it_asset_disposed_trigger
  AFTER UPDATE ON it_assets
  FOR EACH ROW
  EXECUTE FUNCTION it_notify_asset_disposed();
-- Fires when status changes to 'disposed'
```

***

### IT-02: Support Ticketing Events

**Event 1:** `it_ticket_created`\
**Publisher:** IT (IT-02 Support Ticketing)\
**Subscribers:** PF-10 (Notifications)\
**Status:** ✅ Implemented\
**Spec Reference:** [IT-02 IT Support & Ticketing](../../../specs/it/specs/IT-02-it-support-ticketing.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'it_ticket_created';
  ticket_id: uuid;
  ticket_number: string;
  category: 'hardware' | 'software' | 'network' | 'access' | 'email' | 'other';
  priority: 'low' | 'medium' | 'high' | 'critical';
  subject: string;
  requester_id: uuid;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Event 2:** `it_ticket_status_changed`\
**Publisher:** IT (IT-02)\
**Subscribers:** PF-10 (Notifications)\
**Status:** ✅ Implemented\
**Last Verified:** 2026-02-15

**Implementation:**

```sql theme={null}
CREATE TRIGGER it_ticket_status_changed_trigger
  AFTER UPDATE ON it_tickets
  FOR EACH ROW
  EXECUTE FUNCTION it_notify_ticket_status_changed();
```

**Event 3:** `it_ticket_sla_breached`\
**Publisher:** IT (IT-02)\
**Subscribers:** PF-10 (Notifications), IT-02 Dashboard\
**Status:** ✅ Implemented\
**Implemented:** 2026-01-05

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'it_ticket_sla_breached';
  ticket_id: uuid;
  ticket_number: string;
  subject: string;
  organization_id: uuid;
  priority: string;
  status: string;
  assigned_to_profile_id: uuid | null;
  sla_response_target: timestamptz | null;
  sla_resolution_target: timestamptz | null;
  timestamp: timestamptz;
}
```

**Implementation:**

```sql theme={null}
CREATE TRIGGER it_ticket_sla_breached_trigger
  AFTER UPDATE ON it_tickets
  FOR EACH ROW
  WHEN (NEW.sla_breached = true AND (OLD.sla_breached IS NULL OR OLD.sla_breached = false))
  EXECUTE FUNCTION it_notify_ticket_sla_breached();
```

***

### IT-03: Vendor Management Events

**Event:** `it_contract_expiring`\
**Publisher:** IT (IT-03 Vendor Management)\
**Subscribers:** PF-10 (Notifications)\
**Status:** 📝 Planned\
**Spec Reference:** [IT-03 IT Vendor Management](../../../specs/it/specs/IT-03-it-vendor-management.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'it_contract_expiring';
  contract_id: uuid;
  vendor_id: uuid;
  vendor_name: string;
  expiration_date: date;
  days_remaining: number;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

***

### IT-04: Software License Events

**Event 1:** `it_license_created`\
**Publisher:** IT (IT-04 Software License Management)\
**Subscribers:** FA (Finance)\
**Status:** 📝 Planned\
**Spec Reference:** [IT-04 Software License Management](../../../specs/it/specs/IT-04-software-license-management.md)

**Event 2:** `it_license_expiring`\
**Publisher:** IT (IT-04)\
**Subscribers:** PF-10 (Notifications)\
**Status:** 📝 Planned

**Event 3:** `it_license_renewed`\
**Publisher:** IT (IT-04)\
**Subscribers:** FA (Finance)\
**Status:** ✅ Implemented\
**Last Verified:** 2026-02-15

**Implementation:**

```sql theme={null}
CREATE TRIGGER it_license_renewed_trigger
  AFTER UPDATE ON it_licenses
  FOR EACH ROW
  EXECUTE FUNCTION it_notify_license_renewed();
-- Fires when expiry_date is extended
```

**Event 4:** `it_license_compliance_alert`\
**Publisher:** IT (IT-04)\
**Subscribers:** PF-10 (Notifications), FA (cost tracking)\
**Status:** ✅ Implemented\
**Implemented:** 2026-01-05

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'it_license_compliance_alert';
  license_id: uuid;
  organization_id: uuid;
  name: string;
  software_name: string;
  compliance_status: 'non_compliant';
  total_seats: number;
  assigned_seats: number;
  timestamp: timestamptz;
}
```

**Implementation:**

```sql theme={null}
CREATE TRIGGER it_license_compliance_alert_trigger
  AFTER UPDATE ON it_licenses
  FOR EACH ROW
  WHEN (NEW.compliance_status = 'non_compliant' AND (OLD.compliance_status IS NULL OR OLD.compliance_status != 'non_compliant'))
  EXECUTE FUNCTION it_notify_license_compliance_alert();
```

***

### IT-05: Security & Compliance Events

**Event 1:** `it_security_incident_created`\
**Publisher:** IT (IT-05 Security & Compliance)\
**Subscribers:** GR (Governance & Risk), PF-10 (Notifications)\
**Status:** ✅ Implemented\
**Implemented:** 2026-01-05\
**Spec Reference:** [IT-05 IT Security & Compliance](../../../specs/it/specs/IT-05-it-security-compliance.md)

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'it_security_incident_created';
  incident_id: uuid;
  organization_id: uuid;
  severity: 'low' | 'medium' | 'high' | 'critical';
  incident_type: string;
  description: string;
  response_status: string;
  timestamp: timestamptz;
}
```

**Implementation:**

```sql theme={null}
CREATE TRIGGER it_security_incident_created_trigger
  AFTER INSERT ON it_security_incidents
  FOR EACH ROW
  EXECUTE FUNCTION it_notify_security_incident_created();
```

**Event 2:** `it_vulnerability_detected`\
**Publisher:** IT (IT-05)\
**Subscribers:** GR (Governance), PF-10 (Notifications)\
**Status:** ✅ Implemented\
**Implemented:** 2026-01-05

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'it_vulnerability_detected';
  vulnerability_id: uuid;
  organization_id: uuid;
  vulnerability_name: string;
  cve_id: string | null;
  severity: 'critical' | 'high';
  affected_asset_ids: uuid[];
  timestamp: timestamptz;
}
```

**Implementation:**

```sql theme={null}
CREATE TRIGGER it_vulnerability_detected_trigger
  AFTER INSERT ON it_vulnerabilities
  FOR EACH ROW
  WHEN (NEW.severity IN ('critical', 'high'))
  EXECUTE FUNCTION it_notify_vulnerability_detected();
```

**Event 3:** `it_patch_deployed`\
**Publisher:** IT (IT-05)\
**Subscribers:** Event Consumer (audit logging), Asset tracking\
**Status:** ✅ Implemented\
**Implemented:** 2026-01-05

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'it_patch_deployed';
  deployment_id: uuid;
  patch_id: uuid;
  asset_id: uuid;
  organization_id: uuid;
  deployed_at: timestamptz;
  deployed_by: uuid;
  timestamp: timestamptz;
}
```

**Implementation:**

```sql theme={null}
CREATE TRIGGER it_patch_deployed_trigger
  AFTER UPDATE ON it_patch_deployments
  FOR EACH ROW
  WHEN (NEW.status = 'deployed' AND (OLD.status IS NULL OR OLD.status != 'deployed'))
  EXECUTE FUNCTION it_notify_patch_deployed();
```

**Event 4:** `it_patch_deployment_overdue`\
**Publisher:** IT (IT-05)\
**Subscribers:** PF-10 (Notifications)\
**Status:** 📝 Planned

***

### IT-06: Procurement Events

**Event 1:** `it_purchase_request_submitted`\
**Publisher:** IT (IT-06 Procurement)\
**Subscribers:** FW-34 (Approval Workflows), PF-10 (Notifications)\
**Status:** ✅ Implemented\
**Spec Reference:** [IT-06 IT Procurement](../../../specs/it/specs/IT-06-it-procurement.md)

**Event 2:** `it_purchase_request_approved`\
**Publisher:** IT (IT-06)\
**Subscribers:** FA-04 (Purchase Orders), PF-10 (Notifications)\
**Status:** ✅ Implemented

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'it_purchase_request_approved';
  request_id: uuid;
  request_number: string;
  estimated_cost: number;
  vendor_id?: uuid;
  approved_by: uuid;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Event 3:** `it_purchase_request_received`\
**Publisher:** IT (IT-06)\
**Subscribers:** IT-01 (Asset creation), PF-10 (Notifications)\
**Status:** 📝 Planned

***

## Implemented Events (FA Core)

### FA-19: Financial Close Management Events

**Status:** ✅ Complete\
**Implemented:** 2026-01-19

Financial Close Management events are published to the `fa_events` channel for close period lifecycle tracking and task management integration.

#### Event 1: `close_period_started`

**Publisher:** FA (Finance)\
**Subscribers:** PF-10 (Notifications), Audit Log\
**Trigger:** UPDATE on `fa_close_periods` when status changes from 'not\_started' to 'in\_progress'

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_period_started';
  close_period_id: uuid;
  period_name: string;
  period_type: 'month' | 'quarter' | 'year';
  started_by: uuid;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Implementation:**

```sql theme={null}
CREATE TRIGGER trigger_close_period_started
AFTER UPDATE ON fa_close_periods
FOR EACH ROW
EXECUTE FUNCTION fa_publish_close_period_started();
```

#### Event 2: `close_period_completed`

**Publisher:** FA (Finance)\
**Subscribers:** FA-02 (Fiscal Periods), PF-10 (Notifications)\
**Trigger:** UPDATE on `fa_close_periods` when status changes to 'completed'

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_period_completed';
  close_period_id: uuid;
  period_name: string;
  period_type: 'month' | 'quarter' | 'year';
  fiscal_period_id: uuid | null;
  completed_by: uuid;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify FA-02 General Ledger to update fiscal period status, trigger period-end reporting

#### Event 3: `close_period_approved`

**Publisher:** FA (Finance)\
**Subscribers:** FA-07 (Financial Reporting), PF-10 (Notifications)\
**Trigger:** UPDATE on `fa_close_periods` when status changes to 'approved'

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_period_approved';
  close_period_id: uuid;
  period_name: string;
  period_type: 'month' | 'quarter' | 'year';
  fiscal_period_id: uuid | null;
  approved_by: uuid;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Enable final report generation for approved close periods

#### Event 4: `close_task_assigned`

**Publisher:** FA (Finance)\
**Subscribers:** PF-10 (Notifications)\
**Trigger:** UPDATE on `fa_close_tasks` when assigned\_to changes

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_task_assigned';
  task_id: uuid;
  task_name: string;
  checklist_id: uuid;
  close_period_id: uuid;
  assigned_to: uuid;
  assigned_by: uuid;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Notify assigned user of new close task assignment

#### Event 5: `close_task_completed`

**Publisher:** FA (Finance)\
**Subscribers:** PF-10 (Notifications), FA-19 (Progress tracking)\
**Trigger:** UPDATE on `fa_close_tasks` when status changes to 'completed'

**Payload Schema:**

```typescript theme={null}
{
  event_type: 'close_task_completed';
  task_id: uuid;
  task_name: string;
  checklist_id: uuid;
  close_period_id: uuid;
  completed_by: uuid;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**Purpose:** Track close progress, update dashboard metrics, notify stakeholders

**Consumer:** `supabase/functions/event-consumer/index.ts`

* Logs all events to `pf_audit_logs`
* Handlers for notification delivery pending PF-10 integration

**Testing:** ✅ Events fire correctly on status changes

***

### PF-11 / PF-60: Document Lifecycle Events (RAG)

**Status:** ✅ Implemented (triggers and migration)\
**Implemented:** Migration `20260226140000_pf_rag_document_knowledge_events.sql`\
**Spec Reference:** `specs/pf/specs/PF-11-document-management.md`, `docs/architecture/integrations/PF-60-rag-infrastructure-INTEGRATION.md`

For PF-11 and PF-60, events use the **DomainEvent envelope** (see Event Schema Standard above): on the wire, the message has top-level `event_type`, `payload`, and `metadata`. The interfaces below describe the **payload only** (the inner object inside `payload`). Handlers receive the full envelope and use `payload` (and optionally `metadata`); they must not expect `event_type` inside the payload.

#### Events: `document_published`, `document_updated`, `document_deleted`

**Channel:** `domain_events`\
**Publisher:** PF (PF-11)\
**Subscribers:** PF-60 (RAG Infrastructure), Event Consumer\
**Trigger:** INSERT / UPDATE / DELETE on `pf_documents` (see migration for trigger definitions)

##### Payload-only schemas (inside envelope.payload)

```typescript theme={null}
/** Payload only — event_type is at envelope level. */
interface DocumentPublishedPayload {
  organization_id: uuid;
  document_id: uuid;
  timestamp: timestamptz;
  user_id: uuid;
}

interface DocumentUpdatedPayload {
  organization_id: uuid;
  document_id: uuid;
  timestamp: timestamptz;
  user_id: uuid;
}

interface DocumentDeletedPayload {
  organization_id: uuid;
  document_id: uuid;
  timestamp: timestamptz;
  user_id: uuid;
}
```

**Note:** Event payload contains only IDs and non-PHI metadata. RAG consumers (PF-60) must fetch document content (e.g. `extracted_content`, `title`) from `pf_documents` using `document_id` under RLS.

##### Consumer actions

| Consumer                   | Action                            | Status                                                                         |
| -------------------------- | --------------------------------- | ------------------------------------------------------------------------------ |
| PF-60 (RAG Infrastructure) | Generate/update/delete embeddings | 🟡 In Progress (generate-embeddings invoked when event-consumer handler added) |
| Event Consumer             | Log to pf\_audit\_logs            | ✅ Implemented                                                                  |

***

### PF-61: Knowledge Base System Events

**Status:** 📝 Planned\
**Implemented:** TBD\
**Spec Reference:** `specs/pf/specs/PF-61-knowledge-base-system.md`

#### Event: `knowledge_article_published`

**Event:** `knowledge_article_published`\
**Channel:** `domain_events`\
**Publisher:** PF (PF-61)\
**Subscribers:** PF-60 (RAG Infrastructure)\
**Status:** 📝 Planned

##### Purpose

Notifies RAG infrastructure that a knowledge article has been published and is ready for embedding generation.

##### Trigger Conditions

* Article status changes from `draft` or `in_review` to `published` via UPDATE
* **Note:** Event only fires on UPDATE operations when status changes to `published`. Consumers must fetch article details (title, tags, category) under RLS using `article_id`.

##### Payload Schema

```typescript theme={null}
interface KnowledgeArticlePublishedPayload {
  event_type: 'knowledge_article_published';
  organization_id: uuid;
  article_id: uuid;
  timestamp: timestamptz;
  user_id: uuid;
}
```

**Note:** Event payload contains only IDs and non-PII metadata. Consumers must fetch article details (title, tags, category) from `pf_knowledge_base` table using `article_id` under RLS policies.

##### Implementation

```sql theme={null}
CREATE OR REPLACE FUNCTION pf_publish_knowledge_article_published()
RETURNS TRIGGER AS $$
BEGIN
  IF NEW.status = 'published' AND (OLD.status IS NULL OR OLD.status != 'published') THEN
    PERFORM pg_notify('domain_events', json_build_object(
      'event_type', 'knowledge_article_published',
      'organization_id', NEW.organization_id,
      'article_id', NEW.id,
      'timestamp', now(),
      'user_id', NEW.published_by
    )::text);
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER SET search_path = public;

CREATE TRIGGER trigger_knowledge_article_published
AFTER UPDATE ON pf_knowledge_base
FOR EACH ROW
WHEN (OLD.status IS DISTINCT FROM NEW.status AND NEW.status = 'published')
EXECUTE FUNCTION pf_publish_knowledge_article_published();
```

##### Consumer Actions

| Consumer                   | Action                                    | Status        |
| -------------------------- | ----------------------------------------- | ------------- |
| PF-60 (RAG Infrastructure) | Generate embeddings for published article | 📝 Planned    |
| Event Consumer             | Log to pf\_audit\_logs                    | ✅ Implemented |

##### Testing Requirements

* [ ] Event payload structure validation
* [ ] Event fires on publish
* [ ] Correct organization\_id included
* [ ] PF-60 handles event correctly

***

#### Event: `knowledge_article_unpublished`

**Event:** `knowledge_article_unpublished`\
**Channel:** `domain_events`\
**Publisher:** PF (PF-61)\
**Subscribers:** PF-60 (RAG Infrastructure)\
**Status:** 📝 Planned

##### Purpose

Notifies RAG infrastructure to remove embeddings for an unpublished article.

##### Trigger Conditions

* Article status changes from `published` to `draft`, `in_review`, or `archived`
* Article is deleted

##### Payload Schema

```typescript theme={null}
interface KnowledgeArticleUnpublishedPayload {
  event_type: 'knowledge_article_unpublished';
  organization_id: uuid;
  article_id: uuid;
  timestamp: timestamptz;
  user_id: uuid;
}
```

##### Implementation

```sql theme={null}
CREATE OR REPLACE FUNCTION pf_publish_knowledge_article_unpublished()
RETURNS TRIGGER AS $$
BEGIN
  -- Handle UPDATE case: status changes from published to non-published
  IF TG_OP = 'UPDATE' AND NEW.status != 'published' AND OLD.status = 'published' THEN
    PERFORM pg_notify('domain_events', json_build_object(
      'event_type', 'knowledge_article_unpublished',
      'organization_id', NEW.organization_id,
      'article_id', NEW.id,
      'timestamp', now(),
      'user_id', auth.uid()
    )::text);
  END IF;
  
  -- Handle DELETE case: article is deleted while published
  IF TG_OP = 'DELETE' AND OLD.status = 'published' THEN
    PERFORM pg_notify('domain_events', json_build_object(
      'event_type', 'knowledge_article_unpublished',
      'organization_id', OLD.organization_id,
      'article_id', OLD.id,
      'timestamp', now(),
      'user_id', auth.uid()
    )::text);
  END IF;
  
  RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER SET search_path = public;

-- Trigger for UPDATE operations
CREATE TRIGGER trigger_knowledge_article_unpublished
AFTER UPDATE ON pf_knowledge_base
FOR EACH ROW
WHEN (OLD.status = 'published' AND NEW.status != 'published')
EXECUTE FUNCTION pf_publish_knowledge_article_unpublished();

-- Trigger for DELETE operations
CREATE TRIGGER trigger_knowledge_article_unpublished_delete
AFTER DELETE ON pf_knowledge_base
FOR EACH ROW
WHEN (OLD.status = 'published')
EXECUTE FUNCTION pf_publish_knowledge_article_unpublished();
```

##### Consumer Actions

| Consumer                   | Action                                    | Status        |
| -------------------------- | ----------------------------------------- | ------------- |
| PF-60 (RAG Infrastructure) | Delete embeddings for unpublished article | 📝 Planned    |
| Event Consumer             | Log to pf\_audit\_logs                    | ✅ Implemented |

##### Testing Requirements

* [ ] Event payload structure validation
* [ ] Event fires on unpublish
* [ ] Correct organization\_id included
* [ ] PF-60 handles event correctly

***

## Planned Events (CL/PM EHR & Practice Management)

**Source:** [EHR\_PM\_PLANNING\_BUNDLE.md](../../../specs/cl/planning/EHR_PM_PLANNING_BUNDLE.md)\
**Status:** 📝 Planned (stubs); payload schemas to be defined in respective CL/PM specs.

### CL/PM Event Summary

| Event Name                               | Channel         | Publisher                | Subscribers                                                                                                        | Spec Reference                                                                                                                                                  | Definition Timeline                                                                                                                                                      | Owner                         |
| ---------------------------------------- | --------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------- |
| assessment\_completed                    | cl\_pm\_events  | CL                       | PM (optional), FW, PF-10                                                                                           | [CL-02](../../../specs/cl/specs/CL-02-comprehensive-assessments.md)                                                                                             | Q2 2026; payload schema by sprint per CL-02                                                                                                                              | CL team; tracking: CL-02 spec |
| treatment\_plan\_signed                  | cl\_pm\_events  | CL                       | FW, PF-10                                                                                                          | [CL-03](../../../specs/cl/specs/CL-03-treatment-planning.md)                                                                                                    | Q2 2026                                                                                                                                                                  | CL team                       |
| treatment\_plan\_review\_scheduled       | cl\_pm\_events  | CL                       | PF-10                                                                                                              | [CL-03](../../../specs/cl/specs/CL-03-treatment-planning.md)                                                                                                    | Q2 2026                                                                                                                                                                  | CL team                       |
| treatment\_plan\_event\_triggered        | cl\_pm\_events  | CL                       | PF-10                                                                                                              | [CL-03](../../../specs/cl/specs/CL-03-treatment-planning.md)                                                                                                    | Q2 2026                                                                                                                                                                  | CL team                       |
| progress\_note\_signed                   | cl\_pm\_events  | CL                       | PM (charge capture), PF-10                                                                                         | [CL-04](../../../specs/cl/specs/CL-04-progress-notes-session-documentation.md)                                                                                  | Q2 2026                                                                                                                                                                  | CL team                       |
| medication\_recon\_completed             | cl\_pm\_events  | CL                       | PF-10                                                                                                              | [CL-05](../../../specs/cl/specs/CL-05-medication-management-reconciliation.md)                                                                                  | Q2 2026                                                                                                                                                                  | CL team                       |
| prescription\_sent                       | cl\_pm\_events  | CL                       | PM, PF-10                                                                                                          | [CL-06](../../../specs/cl/specs/CL-06-e-prescribing-epcs.md)                                                                                                    | Q2 2026                                                                                                                                                                  | CL team                       |
| pdmp\_query\_completed                   | cl\_pm\_events  | CL / external            | CL (audit)                                                                                                         | [CL-17](../../../specs/cl/specs/CL-17-arizona-cspmp-pdmp-integration.md)                                                                                        | Q2 2026; Dec 31, 2026 CSPMP deadline                                                                                                                                     | CL team                       |
| cds\_alert\_triggered                    | cl\_events      | CL (CL-08)               | PF-10, CL (audit)                                                                                                  | [CL-08](../../../specs/cl/specs/CL-08-clinical-decision-support.md)                                                                                             | Q2 2026                                                                                                                                                                  | CL team                       |
| cds\_rule\_overridden                    | cl\_events      | CL (CL-08)               | PF-10, PF-04 (audit)                                                                                               | [CL-08](../../../specs/cl/specs/CL-08-clinical-decision-support.md)                                                                                             | Q2 2026                                                                                                                                                                  | CL team                       |
| cl\_group\_encounters\_approved          | cl\_events      | CL (CL-14-EN-01)         | PM-07                                                                                                              | [CL-14-EN-01](../../../specs/cl/specs/CL-14-EN-01-group-note-encounter-charge-generation.md)                                                                    | Q2 2026                                                                                                                                                                  | CL team                       |
| cl\_cohort\_membership\_recomputed       | cl\_events      | CL (CL-54)               | CE-09/10 (outreach audience refresh), FA (VBP attribution), CL-35 (panel/dashboard refresh)                        | [CL-54](../../../specs/cl/specs/CL-54-patient-cohort-clinical-registry.md)                                                                                      | Q2 2026                                                                                                                                                                  | CL team                       |
| cl\_quality\_measure\_period\_calculated | cl\_events      | CL (CL-35)               | FA (VBP payment adjustment)                                                                                        | [CL-35](../../../specs/cl/specs/CL-35-population-health-care-gap-management.md) · [CL-FA-VBP-QUALITY-DATA-PIPELINE](./CL-FA-VBP-QUALITY-DATA-PIPELINE.md)       | Phase 3 (shipped 2026-04-01)                                                                                                                                             | CL team                       |
| cl\_care\_gap\_closed                    | cl\_events      | CL (CL-35)               | FW (event automation)                                                                                              | [CL-35](../../../specs/cl/specs/CL-35-population-health-care-gap-management.md) · [CL-FW-EVENT-AUTOMATION-INTEGRATION](./CL-FW-EVENT-AUTOMATION-INTEGRATION.md) | Phase 2 (shipped 2026-04-01)                                                                                                                                             | CL team                       |
| cl\_virtual\_group\_started              | cl\_pm\_events  | CL (CL-55)               | PM-07, PF-10/FW-16 (optional)                                                                                      | [CL-55](../../../specs/cl/specs/CL-55-virtual-telehealth-group-therapy.md)                                                                                      | Q2 2026; PHI-free payload                                                                                                                                                | CL team                       |
| cl\_virtual\_group\_concluded            | cl\_pm\_events  | CL (CL-55)               | PM-07 (charge capture w/ jurisdiction-resolved modifier suggestions)                                               | [CL-55](../../../specs/cl/specs/CL-55-virtual-telehealth-group-therapy.md)                                                                                      | Q2 2026; PHI-free payload                                                                                                                                                | CL team                       |
| cl\_lab\_order\_created                  | cl\_pm\_events  | CL (CL-09)               | PF-10, FW                                                                                                          | [CL-09](../../../specs/cl/specs/CL-09-lab-diagnostic-orders-results.md)                                                                                         | Q2 2026                                                                                                                                                                  | CL team                       |
| cl\_lab\_result\_received                | cl\_pm\_events  | CL (CL-09) / External    | CL-08 (abnormal alert), PF-10                                                                                      | [CL-09](../../../specs/cl/specs/CL-09-lab-diagnostic-orders-results.md)                                                                                         | Q2 2026                                                                                                                                                                  | CL team                       |
| cl\_lab\_result\_reviewed                | cl\_pm\_events  | CL (CL-09)               | PF-10, PF-04 (audit)                                                                                               | [CL-09](../../../specs/cl/specs/CL-09-lab-diagnostic-orders-results.md)                                                                                         | Q2 2026                                                                                                                                                                  | CL team                       |
| cl\_cda\_document\_generated             | cl\_events      | CL (CL-48)               | CL-25 (Audit Dashboard), PF-04 (audit)                                                                             | [CL-48](../../../specs/cl/specs/CL-48-clinical-document-architecture-cda.md) · [INTEGRATION](./clinical-document-architecture-cda-integration.md)               | Q3 2026; PHI-free payload (IDs only)                                                                                                                                     | CL team                       |
| cl\_cda\_transmission\_status\_changed   | cl\_events      | CL (CL-48 edge function) | PF-10 Notifications, CL-25 (Audit Dashboard)                                                                       | [CL-48](../../../specs/cl/specs/CL-48-clinical-document-architecture-cda.md) · [INTEGRATION](./clinical-document-architecture-cda-integration.md)               | Q3 2026; PHI-free payload (IDs + status only)                                                                                                                            | CL team                       |
| cl\_problem\_list\_updated               | cl\_events      | CL (CL-46)               | CL-08 (CDS re-evaluation), PM-07 (advisory — diagnosis pre-pop via `@/platform/clinical#usePatientActiveProblems`) | [CL-46](../../../specs/cl/specs/CL-46-problem-list-management-icd10.md)                                                                                         | Q2 2026; PHI-free payload `&#123; patient_id, problem_id, icd10_code, action: 'added'\|'resolved'\|'reactivated' &#125;`; idempotency key `problem_id+action+changed_at` | CL team                       |
| claim\_submitted                         | cl\_pm\_events  | PM                       | FA (optional), PF-10, FW-03                                                                                        | [PM-08](../../../specs/pm/specs/PM-08-claims-management-submission.md)                                                                                          | Q2 2026                                                                                                                                                                  | PM team                       |
| claim\_status\_changed                   | cl\_pm\_events  | PM                       | PM-09, PF-10, FW-03                                                                                                | [PM-08](../../../specs/pm/specs/PM-08-claims-management-submission.md), [PM-19](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md)         | Q2 2026                                                                                                                                                                  | PM team                       |
| claim\_created                           | cl\_pm\_events  | PM                       | FW-03 (optional)                                                                                                   | [PM-08](../../../specs/pm/specs/PM-08-claims-management-submission.md), [PM-19](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md)         | Q2 2026                                                                                                                                                                  | PM team                       |
| claim\_adjudicated                       | cl\_pm\_events  | PM                       | PM-09, PF-10                                                                                                       | [PM-08](../../../specs/pm/specs/PM-08-claims-management-submission.md), [PM-09](../../../specs/pm/specs/PM-09-payment-posting-era-processing.md)                | Q2 2026                                                                                                                                                                  | PM team                       |
| denial\_received                         | cl\_pm\_events  | PM                       | FW-03, PF-10                                                                                                       | [PM-08](../../../specs/pm/specs/PM-08-claims-management-submission.md), [PM-19](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md)         | Q2 2026                                                                                                                                                                  | PM team                       |
| charge\_approved                         | cl\_pm\_events  | PM                       | FW-03, PF-10                                                                                                       | [PM-07](../../../specs/pm/specs/PM-07-charge-capture-fee-schedules.md), [PM-19](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md)         | Q2 2026                                                                                                                                                                  | PM team                       |
| charge\_status\_changed                  | cl\_pm\_events  | PM                       | FW-03, PF-10                                                                                                       | [PM-07](../../../specs/pm/specs/PM-07-charge-capture-fee-schedules.md), [PM-19](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md)         | Q2 2026                                                                                                                                                                  | PM team                       |
| prior\_auth\_required                    | cl\_pm\_events  | PM                       | CL, PF-10                                                                                                          | [PM-10](../../../specs/pm/specs/PM-10-prior-authorization-management.md)                                                                                        | Q2 2026                                                                                                                                                                  | PM team                       |
| prior\_auth\_received                    | cl\_pm\_events  | PM                       | CL, PM-07/08, PF-10                                                                                                | [PM-10](../../../specs/pm/specs/PM-10-prior-authorization-management.md)                                                                                        | Q2 2026                                                                                                                                                                  | PM team                       |
| eligibility\_verified                    | cl\_pm\_events  | PM                       | CL, PM-07, PF-10                                                                                                   | [PM-02](../../../specs/pm/specs/PM-02-insurance-eligibility-verification.md)                                                                                    | Q2 2026                                                                                                                                                                  | PM team                       |
| patient\_registered                      | cl\_pm\_events  | PM                       | CL, RH (optional), PF-10                                                                                           | [PM-01](../../../specs/pm/specs/PM-01-patient-registration-demographics.md)                                                                                     | Q2 2026                                                                                                                                                                  | PM team                       |
| appointment\_scheduled                   | cl\_pm\_events  | PM                       | CL, PF-10                                                                                                          | [PM-03](../../../specs/pm/specs/PM-03-appointment-scheduling.md)                                                                                                | Q2 2026                                                                                                                                                                  | PM team                       |
| encounter\_completed                     | cl\_pm\_events  | CL/PM                    | PM (charge capture), PF-10                                                                                         | [CL-04](../../../specs/cl/specs/CL-04-progress-notes-session-documentation.md), [PM-07](../../../specs/pm/specs/PM-07-charge-capture-fee-schedules.md)          | Q2 2026                                                                                                                                                                  | CL/PM                         |
| payment\_posted                          | cl\_pm\_events  | PM (PM-09)               | FA, FW-03                                                                                                          | [PM-09](../../../specs/pm/specs/PM-09-payment-posting-era-processing.md), [PM-19](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md)       | Q2 2026                                                                                                                                                                  | PM team                       |
| write\_off\_approved                     | cl\_pm\_events  | PM (PM-09) / PF-10       | FA, FW-03                                                                                                          | [PM-09](../../../specs/pm/specs/PM-09-payment-posting-era-processing.md), [PM-19](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md)       | Q2 2026                                                                                                                                                                  | PM team                       |
| pm.rpa.execution\_completed              | pm\_rpa\_events | PM (PM-51 RPA)           | PM-08, PM-09                                                                                                       | [PM-51](../../../specs/pm/specs/PM-51-payer-portal-automation-rpa.md)                                                                                           | Q3 2026                                                                                                                                                                  | PM team                       |
| pm.rpa.consecutive\_failures             | pm\_rpa\_events | PM (PM-51 RPA)           | PF-10                                                                                                              | [PM-51](../../../specs/pm/specs/PM-51-payer-portal-automation-rpa.md)                                                                                           | Q3 2026                                                                                                                                                                  | PM team                       |

**PM events as automation triggers:** When the `cl_pm_events` channel is implemented, FW-03 Automation Engine can subscribe and use PM events as automation triggers (trigger type `pm_event` or `event` with source PM). Billing admins can create rules that run when specific events occur (e.g. claim status = denied, charge approved, payment posted), with optional payload filters (event\_type, new\_status, payer\_id). See [PM-19: PM-Triggered Business Rule Automation](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md) and [PM-19 Integration](./pm-triggered-business-rule-automation-integration.md).

**CL-23 In-Basket event consumption:** CL-23 (Clinical In-Basket) consumes the following planned events to create or update `cl_inbasket_items` (item types: cosign\_request, lab\_review, refill\_request, chart\_message, referral\_response, cds\_alert). Event names and payload schemas are defined in the rows above; when implemented, CL-23 subscribes and maps to in-basket item\_type and payload. Key events: `progress_note_signed` (cosign), `cds_alert_triggered` (cds\_alert), `cl_lab_result_received` / `cl_lab_result_reviewed` (lab\_review). Planned stubs for referral and chart\_message below. See [CL-23 Clinical In-Basket Integration](./clinical-in-basket-provider-messaging-integration.md).

**CL-23 planned event stubs (referral\_response, chart\_message):**

> ⚠️ **Naming compliance note:** When these events are implemented, names MUST follow the established `{domain}_{entity}_{action}` convention (e.g., `cl_referral_response_received`, `cl_chart_message_sent`). The placeholder names below are for planning only.

| Event Name                                                                   | Channel             | Publisher                     | Subscribers | Payload Schema        | Status     |
| ---------------------------------------------------------------------------- | ------------------- | ----------------------------- | ----------- | --------------------- | ---------- |
| referral\_response (placeholder — rename to `cl_referral_response_received`) | cl\_events (or TBD) | TBD (PM/CL when spec defines) | CL-23       | To be defined in spec | 📝 Planned |
| chart\_message (placeholder — rename to `cl_chart_message_sent`)             | cl\_events (or TBD) | TBD (PM/CL when spec defines) | CL-23       | To be defined in spec | 📝 Planned |

Consumers can align on channel, publisher, subscriber, and payload placeholders early; payload schemas will be defined in respective PM/CL specs.

**PM-19 automation trigger payload schemas (canonical):** All PM events consumed by FW-03 for automation MUST include `organization_id` in payload or metadata for tenant isolation. Filterable fields used by PM-19 rules:

| Event Type              | Required Payload Fields                                            | Optional Filter Fields (for rule matching) |
| ----------------------- | ------------------------------------------------------------------ | ------------------------------------------ |
| `claim_submitted`       | `organization_id`, `claim_id`, `payer_id`                          | `payer_id`                                 |
| `claim_status_changed`  | `organization_id`, `claim_id`, `new_status`, `payer_id`            | `new_status`, `payer_id`                   |
| `claim_created`         | `organization_id`, `claim_id`, `payer_id`                          | `payer_id`                                 |
| `denial_received`       | `organization_id`, `claim_id`, `payer_id`                          | `payer_id`                                 |
| `charge_approved`       | `organization_id`, `charge_id`                                     | —                                          |
| `charge_status_changed` | `organization_id`, `charge_id`, `new_status`                       | `new_status`                               |
| `payment_posted`        | `organization_id`, `payment_id`, `claim_id`                        | —                                          |
| `write_off_approved`    | `organization_id`, `approval_id`, `payment_id`, `write_off_amount` | —                                          |

**IDs-only rule for PM automation payloads:** All example payloads in this subsection use **UUIDs/IDs only** (no PII/PHI). Human-readable identifiers (e.g. claim numbers, account numbers) must not be included in event payloads; use system-generated UUIDs only, or if needed store only irreversible hashes. Consumers resolve display data via authorized APIs.

**Example payload (claim\_status\_changed):**

```typescript theme={null}
{
  event_id: uuid;
  event: 'claim_status_changed';
  payload: {
    organization_id: uuid;
    claim_id: uuid;
    patient_id: uuid;
    payer_id: uuid;
    previous_status: string;
    new_status: string;   // Used by PM-19 filter (e.g. 'denied', 'paid')
    denial_codes?: Array<{ code: string; source: string }>;
    paid_amount?: number; // cents, when new_status = 'paid'
    changed_by?: uuid;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

**Example payload (charge\_approved / charge\_status\_changed):**

```typescript theme={null}
{
  event_id: uuid;
  event: 'charge_approved' | 'charge_status_changed';
  payload: {
    organization_id: uuid;
    charge_id: uuid;
    new_status?: string;   // For charge_status_changed: e.g. 'approved', 'pending'
    patient_id?: uuid;
    encounter_id?: uuid;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

**Example payload (payment\_posted):**

```typescript theme={null}
{
  event_id: uuid;
  event: 'payment_posted';
  payload: {
    organization_id: uuid;
    payment_id: uuid;
    claim_id?: uuid;
    amount_cents: number;
    payer_id?: uuid;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

All example payloads above use **IDs only** (no PII/PHI). Automation actions resolve display data via authorized APIs.

**Acceptance criteria for transition to full specs:** (1) Payload schema documented with required/optional fields and types; (2) Channel `cl_pm_events` created and wired; (3) Publisher/subscriber contracts and error handling agreed; (4) Owner and target date (sprint/quarter) assigned per row above.

### CL/PM Full Payload Schemas (Canonical)

Payloads use **IDs only** (no PII/PHI). All events include `event_id` (uuid) as the primary idempotency key and `metadata: { organization_id, user_id?, timestamp, correlation_id? }`. **Idempotency note:** `event_id` is the canonical deduplication key per the Event Schema Standard. Some older event contracts reference `correlation_id` for idempotency — these should be treated as supplementary domain-specific keys; `event_id` takes precedence.

#### clinical\_note\_finalized (CL-04 → PM-07)

**Event:** `clinical_note_finalized` (alias: `progress_note_signed`)\
**Publisher:** CL\
**Subscribers:** PM-07 (charge capture), PF-10\
**Contract:** [CL-PM-ENCOUNTER-TO-BILLING](./CL-PM-ENCOUNTER-TO-BILLING.md)

```typescript theme={null}
{
  event_id: uuid;
  event: 'clinical_note_finalized';
  payload: {
    encounter_id: uuid;
    patient_id: uuid;
    provider_id: uuid;
    note_id: uuid;
    service_date: string; // ISO date
    begin_time: string;   // ISO time or HH:mm
    end_time: string;
    duration_minutes: number;
    cpt_code: string;
    diagnosis_codes: string[];
    place_of_service: string;
    is_telehealth: boolean;
    is_group: boolean;
    group_participant_count?: number;
    modifiers: string[];
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

**Idempotency:** Consumer (PM-07) MUST use `event_id` to avoid duplicate charges. **Error handling:** Retry with exponential backoff; dead-letter queue after N failures. **No PII/PHI in payload.**

#### peer\_encounter\_finalized (CL-19 → PM-07)

**Event:** `peer_encounter_finalized`\
**Publisher:** CL\
**Subscribers:** PM-07 (charge capture)\
**Contract:** [CL-19 Peer Recovery Support](./peer-recovery-support-services-integration.md)

```typescript theme={null}
{
  event_id: uuid;
  event: 'peer_encounter_finalized';
  payload: {
    event_type: 'peer_encounter_finalized';
    timestamp: string;   // ISO timestamp
    user_id?: uuid;      // present only when the event is user-initiated; otherwise omit
    peer_encounter_id: uuid;
    organization_id: uuid;
    chart_id: uuid;
    encounter_id?: uuid;  // optional link to pm_encounters
    peer_provider_id: uuid;
    service_date: string;   // ISO date
    hcpcs_code: string;
    duration_minutes: number;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

**Idempotency:** Consumer (PM-07) MUST use `event_id` to avoid duplicate charges. **No PII/PHI in payload.** `payload.user_id` is set only when the event is user-initiated; otherwise omit.

#### assessment\_completed (CL-02)

```typescript theme={null}
{
  event_id: uuid;
  event: 'assessment_completed';
  payload: {
    assessment_id: uuid;
    patient_id: uuid;
    assessment_type: string;
    level_of_care_recommendation?: string;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### treatment\_plan\_signed (CL-03)

```typescript theme={null}
{
  event_id: uuid;
  event: 'treatment_plan_signed';
  payload: {
    plan_id: uuid;
    patient_id: uuid;
    signed_by: uuid;
    signature_type: 'member' | 'hcdm' | 'clinician';
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### consent\_granted / consent\_revoked (CL-11)

```typescript theme={null}
{
  event_id: uuid;
  event: 'consent_granted' | 'consent_revoked';
  payload: {
    consent_id: uuid;
    patient_id: uuid;
    consent_type: string;
    scope: string;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### cl\_sdoh\_screening\_completed (CL-18)

Consumers MUST resolve patient identity from `chart_id` (e.g. `cl_sdoh_screenings.chart_id` → `cl_patient_charts`). `patient_id` is not in the payload to avoid denormalization and sync/merge issues.

```typescript theme={null}
{
  event_id: uuid;
  event: 'cl_sdoh_screening_completed';
  payload: {
    screening_id: uuid;
    chart_id: uuid;   // primary reference; resolve patient via cl_patient_charts
    needs_identified: string[];
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### patient\_registered (PM-01)

```typescript theme={null}
{
  event_id: uuid;
  event: 'patient_registered';
  payload: {
    patient_id: uuid;
    patient_identity_id?: uuid;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### appointment\_scheduled (PM-03)

```typescript theme={null}
{
  event_id: uuid;
  event: 'appointment_scheduled';
  payload: {
    appointment_id: uuid;
    patient_id: uuid;
    provider_id: uuid;
    start_datetime: string;
    end_datetime: string;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### encounter\_completed (PM-03 / CL-04)

```typescript theme={null}
{
  event_id: uuid;
  event: 'encounter_completed';
  payload: {
    encounter_id: uuid;
    patient_id: uuid;
    appointment_id?: uuid;
    status: string;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### cl\_assessment\_completed (CL-02-EN-59)

**Event:** `cl_assessment_completed`\
**Channel:** `cl_events`\
**Publisher:** CL-02\
**Subscribers:** PM-07 (charge capture for assessment billing)\
**Status:** ✅ Active (2026-04-04)

Payload includes `instrument_code` to allow subscribers to differentiate cognitive screening instruments (moca, slums, mmse) from other assessments. No PHI in payload — consumers must fetch clinical data server-side.

```typescript theme={null}
{
  event_id: uuid;
  event: 'cl_assessment_completed';
  payload: {
    assessment_id: uuid;
    chart_id: uuid;
    instrument_code: string;       // e.g. 'moca', 'slums', 'mmse'
    instrument_name: string;       // Human-readable name
    score: number | null;          // Adjusted score (null if draft)
    below_threshold: boolean;      // true if score below population threshold
    completed_by: uuid;            // User ID of clinician
    completed_at: timestamptz;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

***

#### claim\_submitted / claim\_status\_changed (PM-08)

```typescript theme={null}
{
  event_id: uuid;
  event: 'claim_submitted' | 'claim_status_changed';
  payload: {
    claim_id: uuid;
    claim_number: string;
    patient_id: uuid;
    payer_id: uuid;
    claim_type: 'professional_837p' | 'institutional_837i';
    total_charge: number;
    line_count: number;        // Number of claim lines
    submitted_by?: uuid;       // User who submitted (claim_submitted only)
    new_status?: string;       // New status (claim_status_changed only)
    changed_by?: uuid;         // User who changed status (claim_status_changed only)
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### prior\_auth\_required / prior\_auth\_received (PM-10)

```typescript theme={null}
{
  event_id: uuid;
  event: 'prior_auth_required' | 'prior_auth_received';
  payload: {
    prior_authorization_id: uuid;
    patient_id: uuid;
    status: string;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### eligibility\_verified (PM-02)

```typescript theme={null}
{
  event_id: uuid;
  event: 'eligibility_verified';
  payload: {
    eligibility_check_id: uuid;
    patient_id: uuid;
    policy_id?: uuid;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### charge\_approved / charge\_status\_changed (PM-07 → FW-03)

**Event:** `charge_approved` or `charge_status_changed`\
**Publisher:** PM (PM-07)\
**Subscribers:** FW-03 (automation triggers), PF-10\
**Spec Reference:** [PM-19 PM-Triggered Business Rule Automation](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md)

```typescript theme={null}
{
  event_id: uuid;
  event: 'charge_approved' | 'charge_status_changed';
  payload: {
    charge_id: uuid;
    patient_id: uuid;
    organization_id: uuid;
    new_status: string;        // e.g. 'approved', 'billed', 'void'
    old_status?: string;       // charge_status_changed only
    changed_by?: uuid;
    payer_id?: uuid;           // from fee schedule when applicable
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### claim\_created (PM-08)

**Event:** `claim_created`\
**Publisher:** PM (PM-08)\
**Subscribers:** FW-03 (optional)\
**Spec Reference:** [PM-19](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md)

```typescript theme={null}
{
  event_id: uuid;
  event: 'claim_created';
  payload: {
    claim_id: uuid;
    claim_number: string;
    patient_id: uuid;
    payer_id: uuid;
    status: string;            // 'draft'
    created_by?: uuid;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### denial\_received (PM-08 / PM-09)

**Event:** `denial_received`\
**Publisher:** PM (PM-08/PM-09 when denial\_codes updated, e.g. from ERA)\
**Subscribers:** FW-03, PF-10\
**Spec Reference:** [PM-19](../../../specs/pm/specs/PM-19-pm-triggered-business-rule-automation.md)

```typescript theme={null}
{
  event_id: uuid;
  event: 'denial_received';
  payload: {
    claim_id: uuid;
    claim_number: string;
    payer_id: uuid;
    new_status: string;        // e.g. 'denied'
    denial_codes?: Array<{ carc: string; rarc?: string; group_code: string }>;
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

#### payment\_posted (PM-09 → FA)

**Event:** `payment_posted`\
**Channel:** `cl_pm_events`\
**Publisher:** PM (PM-09)\
**Subscribers:** FA (revenue/AR posting to GL)\
**Status:** Implemented (FA consumer: fa-consume-pm-payment-events)\
**Spec Reference:** [PM-09 Payment Posting & ERA Processing](../../../specs/pm/specs/PM-09-payment-posting-era-processing.md)\
**Integration Doc:** [PM-09 Integration](./payment-posting-era-processing-integration.md)

**Purpose:** Notify FA when an insurance or patient payment has been posted so FA can post revenue/AR to the general ledger. Loose coupling: PM publishes after posting; FA consumes asynchronously.

**Trigger:** After `pm_payments` row is created/updated with status 'posted' or 'partially\_posted' and at least one `pm_payment_applications` exists (or after ERA batch posting completes).

**Payload Schema:**

```typescript theme={null}
{
  event_id: uuid;
  event: 'payment_posted';
  payload: {
    payment_id: uuid;
    organization_id: uuid;
    payment_type: 'insurance' | 'patient' | 'adjustment' | 'refund';
    total_amount: number;
    posted_amount: number;
    payment_date: string;   // ISO date
    payer_id: uuid | null;  // pm_payers.id if insurance
    patient_id: uuid | null;
    era_file_id: uuid | null;
    claim_ids: uuid[];      // claims affected (for FA to link GL lines)
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

**Idempotency:** FA MUST use `event_id` to avoid duplicate GL entries. **No PII/PHI in payload** (IDs only).

#### write\_off\_approved (PM-09 / PF-10 → FA)

**Event:** `write_off_approved`\
**Channel:** `cl_pm_events`\
**Publisher:** PM (PM-09) or PF-10 (approval workflow completion)\
**Subscribers:** FA (write-off/bad debt GL entry)\
**Status:** Implemented (FA consumer: fa-consume-pm-payment-events)\
**Spec Reference:** [PM-09 Payment Posting & ERA Processing](../../../specs/pm/specs/PM-09-payment-posting-era-processing.md)\
**Integration Doc:** [PM-09 Integration](./payment-posting-era-processing-integration.md)

**Purpose:** Notify FA when a write-off or bad debt has been approved (PF-10/FW-34) so FA can post the write-off to the general ledger.

**Trigger:** When platform approval (PF-10/FW-34) completes for a write-off request tied to PM-09 (e.g. payment or application write-off).

**Payload Schema:**

```typescript theme={null}
{
  event_id: uuid;
  event: 'write_off_approved';
  payload: {
    approval_id: uuid;      // PF-10 approval record
    organization_id: uuid;
    payment_id: uuid;       // pm_payments.id (write_off type)
    write_off_amount: number;
    claim_id: uuid | null;
    reason_code?: string;   // optional adjustment/reason code
  };
  metadata: { organization_id: uuid; user_id?: uuid; timestamp: timestamptz; correlation_id?: uuid; };
}
```

**Idempotency:** FA MUST use `event_id` to avoid duplicate write-off GL entries. **No PII/PHI in payload** (IDs only).

***

### Planned Events (FA Cross-Core — when CE/GR/CL ready)

| Event                             | Publisher | Consumer                         | Spec                                                                                                                                                        | Status                                                                              |
| --------------------------------- | --------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `donation_received`               | CE        | FA-05, FA-02                     | [CE-18](../../../specs/ce/specs/CE-18-fundraising-donation-events-fa.md), [FA-31](../../../specs/fa/specs/FA-31-ce-fa-donation-revenue-integration.md)      | 📝 Planned                                                                          |
| `fundraising_campaign_completed`  | CE        | FA-07                            | [CE-18](../../../specs/ce/specs/CE-18-fundraising-donation-events-fa.md), [FA-31](../../../specs/fa/specs/FA-31-ce-fa-donation-revenue-integration.md)      | 📝 Planned                                                                          |
| `compliance_cost_incurred`        | GR        | FA-13, FA-15                     | [FA-34](../../../specs/fa/specs/FA-34-gr-fa-compliance-cost-tracking.md)                                                                                    | 📝 Planned                                                                          |
| `clinical_program_cost_allocated` | CL        | FA-35 (→ FA-15 allocation bases) | [FA-35](../../../specs/fa/specs/FA-35-cl-fa-clinical-program-cost-allocation.md)                                                                            | 📝 Planned                                                                          |
| `encounter_cost_calculated`       | PM-35     | FA-35 (Phase 2)                  | [PM-35](../../../specs/pm/specs/PM-35-encounter-level-cost-accounting.md), [FA-35](../../../specs/fa/specs/FA-35-cl-fa-clinical-program-cost-allocation.md) | 📝 Planned — schema pending FA-35 + PM-35 joint session (see PENDING\_CONTRACTS.md) |

#### `clinical_program_cost_allocated` — Payload Schema

**Channel:** `cl_events`
**Publisher:** CL (Clinical core)
**Publisher Artifact:** TBD — CL edge function or trigger (pending CL module maturity)
**Subscriber:** FA-35 (`fa-consume-cl-program-cost` edge function)
**Subscriber Artifact:** `supabase/functions/fa-consume-cl-program-cost/index.ts` (FA-35)
**Idempotency Key:** `event_id` (UUID); consumer deduplicates on `fa_cl_allocation_activity.source_event_id`.

```typescript theme={null}
{
  event_id: uuid;                   // Required; unique per event
  event: 'clinical_program_cost_allocated';
  version: '1.0';
  payload: {
    organization_id: uuid;          // Tenant isolation — required
    program_id: uuid;               // CL clinical program UUID (opaque to FA)
    activity_count: number;         // Encounter/session count for the period
    period_start: string;           // ISO date (YYYY-MM-DD)
    period_end: string;             // ISO date (YYYY-MM-DD)
  };
  metadata: {
    organization_id: uuid;
    user_id?: uuid;
    timestamp: string;              // ISO timestamp
    correlation_id?: uuid;
  };
}
```

**Implementation Location:**

* **Publisher:** TBD — CL edge function or database trigger (pending CL module implementation)
* **Subscriber:** `supabase/functions/fa-consume-cl-program-cost/index.ts` (FA-35 Phase 1)

**Contract References:**

* [FA-35 CL-FA Clinical Program Cost Allocation](../../../specs/fa/specs/FA-35-cl-fa-clinical-program-cost-allocation.md)
* Subscriber identifier: FA-35

**No PHI/PII:** Only program UUIDs and integer counts. No patient names, diagnoses, or clinical details.

#### `encounter_cost_calculated` — Payload Schema

**Channel:** `fa_events` (or `cl_pm_events` — to be confirmed)
**Publisher:** PM-35 (Practice Management / Encounter Cost Accounting)
**Subscriber:** FA-35 (`fa-consume-encounter-cost` edge function)
**Idempotency Key:** `event_id` (UUID); consumer deduplicates on `event_id` (or `source_event_id` if included in payload).
**Status:** 📝 Planned — schema pending FA-35 + PM-35 joint session (see PENDING\_CONTRACTS.md)

**Payload Schema (draft):**

```typescript theme={null}
{
  event_id: uuid;                   // Required; unique per event
  event: 'encounter_cost_calculated';
  version: '1.0';
  payload: {
    organization_id: uuid;          // Tenant isolation — required
    encounter_id: uuid;             // PM encounter UUID (opaque to FA)
    cl_program_id?: uuid;           // CL program identifier (pending PM-35 confirmation)
    cost_breakdown: {
      total_cost: number;           // Total encounter cost
      // Additional fields TBD in PM-35/FA-35 joint session
    };
    period_start: string;           // ISO date (YYYY-MM-DD)
    period_end: string;             // ISO date (YYYY-MM-DD)
  };
  metadata: {
    organization_id: uuid;
    user_id?: uuid;
    timestamp: string;              // ISO timestamp
    correlation_id?: uuid;
  };
}
```

**Implementation Location:**

* **Publisher:** TBD — PM-35 edge function or trigger (pending PM-35 Phase 2)
* **Subscriber:** `supabase/functions/fa-consume-encounter-cost/index.ts` (FA-35 Phase 2)

**Contract References:**

* [PM-35 Encounter-Level Cost Accounting](../../../specs/pm/specs/PM-35-encounter-level-cost-accounting.md)
* [FA-35 CL-FA Clinical Program Cost Allocation](../../../specs/fa/specs/FA-35-cl-fa-clinical-program-cost-allocation.md)
* [PM-35 Integration Doc](./cost-accounting-integration.md)

**No PHI/PII:** Only UUIDs and cost amounts. No patient names, clinical details, or diagnoses.

***

### CL/PM Event Error Handling and Idempotency

* **Idempotency:** Every event MUST include a unique `event_id`. Consumers MUST record processed `event_id`s and MUST NOT create duplicate side effects (e.g. duplicate charges) when the same event is delivered more than once.
* **Retry policy:** Consumers SHOULD retry transient failures with exponential backoff (e.g. 1s, 2s, 4s, max 3 retries).
* **Dead-letter queue (DLQ):** After max retries, event SHOULD be written to a DLQ or logged for manual resolution; alert operators.
* **No PII/PHI in payload:** Only UUIDs and non-identifying codes. See constitution and EVENT\_CONTRACTS security guidance.

***

### Example Stub: assessment\_completed

**Event:** `assessment_completed`\
**Channel:** `cl_pm_events`\
**Publisher:** CL (Clinical & EHR)\
**Subscribers:** PM (optional billing), FW, PF-10\
**Status:** 📝 Planned\
**Spec Reference:** [CL-02 – Comprehensive Assessments](../../../specs/cl/specs/CL-02-comprehensive-assessments.md)\
**Definition Timeline:** Q2 2026; payload schema finalized in CL-02 spec.\
**Owner:** CL team; tracking: CL-02 spec.

**Purpose:** Notify when a comprehensive assessment is completed so downstream workflows (billing, automation, notifications) can react.

**Trigger Conditions:** Assessment record finalized/signed (e.g. INSERT/UPDATE on assessment table with status = completed).

**Payload Schema (mandatory fields per EVENT\_CONTRACTS guidelines):**

| Field             | Type                   | Required | Description                                                                 |
| ----------------- | ---------------------- | -------- | --------------------------------------------------------------------------- |
| `event_type`      | string                 | Yes      | Must equal `"assessment_completed"`.                                        |
| `organization_id` | uuid                   | Yes      | Tenant isolation; required.                                                 |
| `timestamp`       | timestamptz (ISO 8601) | Yes      | Event occurrence time.                                                      |
| `site_id`         | uuid                   | Optional | If site-scoped.                                                             |
| `user_id`         | uuid                   | Optional | If user-initiated (e.g. completing clinician).                              |
| `correlation_id`  | string (uuid)          | Optional | For event chaining and audit trail.                                         |
| `assessment_id`   | uuid                   | Yes      | Assessment record ID. Event payload must not contain PII/PHI; use IDs only. |
| `patient_id`      | uuid                   | Yes      | Patient record ID. Event payload must not contain PII/PHI; use IDs only.    |

**GUIDANCE:** Event payload must not contain PII/PHI; use IDs only (e.g. `assessment_id`, `patient_id`). No names, emails, or other sensitive data. See [EVENT\_CONTRACTS](./EVENT_CONTRACTS.md) payload guidelines.

**Implementation:** Not yet implemented. Channel `cl_pm_events` to be created when CL/PM event pipeline is implemented.

***

### CL-03: treatment\_plan\_review\_scheduled

**Event:** `treatment_plan_review_scheduled`\
**Channel:** `cl_pm_events`\
**Publisher:** CL (Clinical & EHR)\
**Subscribers:** PF-10 (Notifications)\
**Status:** 📝 Planned\
**Spec Reference:** [CL-03 – Treatment Planning](../../../specs/cl/specs/CL-03-treatment-planning.md)\
**Integration Doc:** [CL-03-treatment-planning-INTEGRATION.md](./treatment-planning-integration.md)\
**Owner:** CL team.

**Purpose:** Notify when a treatment plan is due for review (e.g. 30 days before annual `review_due_date`) so PF-10 can send alerts to the assigned clinician/care coordinator.

**Trigger Conditions:** Scheduled or cron evaluation: plans where `review_due_date` is within the notification window (e.g. 30 days); or on plan create/update when `review_due_date` is set.

**Payload Schema:**

| Field               | Type              | Required | Description                                     |
| ------------------- | ----------------- | -------- | ----------------------------------------------- |
| `event_type`        | string            | Yes      | Must equal `"treatment_plan_review_scheduled"`. |
| `organization_id`   | uuid              | Yes      | Tenant isolation.                               |
| `timestamp`         | string (ISO 8601) | Yes      | Event occurrence time.                          |
| `site_id`           | uuid              | Optional | If site-scoped.                                 |
| `user_id`           | uuid              | Optional | If user-initiated.                              |
| `correlation_id`    | string (uuid)     | Optional | For audit/chain.                                |
| `treatment_plan_id` | uuid              | Yes      | Plan record ID.                                 |
| `chart_id`          | uuid              | Yes      | Patient chart ID.                               |
| `review_due_date`   | string (date)     | Yes      | Date plan review is due.                        |

**Implementation:** Not yet implemented.

***

### CL-03: treatment\_plan\_event\_triggered

**Event:** `treatment_plan_event_triggered`\
**Channel:** `cl_pm_events`\
**Publisher:** CL (Clinical & EHR)\
**Subscribers:** PF-10 (Notifications)\
**Status:** 📝 Planned\
**Spec Reference:** [CL-03 – Treatment Planning](../../../specs/cl/specs/CL-03-treatment-planning.md)\
**Integration Doc:** [CL-03-treatment-planning-INTEGRATION.md](./treatment-planning-integration.md)\
**Owner:** CL team.

**Purpose:** Notify when a life event is recorded that triggers a treatment plan update (hospitalization, move, LOC change, incarceration). Success metric: alert/queue within 48 hours of event recorded. Phase 1: manual event entry only. For auditability, `user_id` must be present when the trigger is user-initiated.

**Trigger Conditions:** User records a qualifying life event for a chart (e.g. "Life event" form or chart event); optional future ADT integration.

**Payload Schema:**

| Field               | Type              | Required | Description                                                                                                                    |
| ------------------- | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `event_type`        | string            | Yes      | Must equal `"treatment_plan_event_triggered"`.                                                                                 |
| `organization_id`   | uuid              | Yes      | Tenant isolation.                                                                                                              |
| `timestamp`         | string (ISO 8601) | Yes      | Event occurrence time.                                                                                                         |
| `site_id`           | uuid              | Optional | If site-scoped.                                                                                                                |
| `user_id`           | uuid              | Yes      | User who recorded the event; required for user-initiated life-event triggers (omit only for explicit system-initiated events). |
| `correlation_id`    | string (uuid)     | Optional | For audit/chain.                                                                                                               |
| `chart_id`          | uuid              | Yes      | Patient chart ID.                                                                                                              |
| `life_event_type`   | string            | Optional | e.g. `hospitalization`, `move`, `loc_change`, `incarceration`.                                                                 |
| `event_recorded_at` | string (ISO 8601) | Yes      | When the event was recorded in the system.                                                                                     |
| `treatment_plan_id` | uuid              | Optional | Current active plan ID if known.                                                                                               |

**Implementation:** Not yet implemented.

***

***

### PM-02: Insurance & Eligibility Verification Events

**Status:** 📝 Planned\
**Spec Reference:** [PM-02-insurance-eligibility-verification.md](../../../specs/pm/specs/PM-02-insurance-eligibility-verification.md)

#### Event: `pm_eligibility_verified`

**Channel:** `pm_events`\
**Publisher:** PM (Practice Management) — PM-02\
**Subscribers:** CL-01 (Patient Chart — coverage info update), PM-08 (Claims — eligibility gate)\
**Trigger:** After an eligibility check record is created and `eligible` field is set\
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
interface EligibilityVerifiedPayload {
  event_type: 'pm_eligibility_verified';
  organization_id: string;       // Tenant isolation (UUID)
  patient_id: string;            // UUID — patient identifier only; no PHI in payload
  policy_id: string | null;      // UUID — policy checked (null for manual/unlinked checks)
  check_id: string;              // UUID — pm_eligibility_checks.id
  eligible: boolean;             // Whether patient is currently eligible
  response_status: string;       // e.g. 'active_coverage', 'inactive', 'not_found', 'error'
  check_type: 'real_time' | 'batch' | 'manual';
  next_check_due: string | null; // ISO 8601 — when to re-verify; null if unknown
  timestamp: string;             // ISO 8601 — event occurrence time
}
```

**PHI Logging Guidelines:**

* **Allowed:** `check_id`, `patient_id` (UUID only — no name/DOB), `check_type`, `eligible`, `organization_id`
* **Prohibited:** `benefit_details` contents, `policy_number`, `subscriber_dob`, `subscriber_name`
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs or edge function stdout

**Consumer Actions:**

1. **CL-01:** Update patient chart coverage status display (coverage info widget)
2. **PM-08:** Allow/block claim submission based on eligibility status (eligibility gate)
3. **FW automations:** Trigger workflows on eligibility change (e.g., notify staff of inactive coverage)

**Implementation Note:**

* Register in `fw_workflow_events` table via seed migration (Phase 0, T0 task)
* Channel `pm_events` must be added to the Event Delivery Mechanism channel list
* Published via `publishEvent()` from `@/platform/events` after eligibility check record creation

***

#### Event: `pm_benefits_parsed`

**Channel:** `pm_events`
**Publisher:** PM (Practice Management) — PM-02-EN-02 (`pm-parse-271-benefits` edge function)
**Subscribers:** PM-48 (Patient Cost Estimation & Financial Clearance), PM-07 (Charge Capture — copay/deductible defaults)
**Trigger:** After successful X12 271 EB-loop parsing and persistence of `pm_benefit_details` rows for an eligibility check
**Status:** 📝 Planned (PM-02-EN-02)
**Spec Reference:** [PM-02-EN-02-eligibility-benefit-detail-parsing.md](../../../specs/pm/specs/PM-02-EN-02-eligibility-benefit-detail-parsing.md) §FR-3.3

**Payload Schema:**

```typescript theme={null}
interface BenefitsParsedPayload {
  event_type: 'pm_benefits_parsed';
  organization_id: string;          // Tenant isolation (UUID)
  eligibility_check_id: string;     // UUID — pm_eligibility_checks.id
  patient_id: string;               // UUID — patient identifier only; no PHI in payload
  service_types_parsed: string[];   // X12 service type codes for which EB loops were extracted
  parsing_confidence: 'high' | 'medium' | 'low';
  benefit_detail_ids: string[];     // UUIDs of pm_benefit_details rows written
  timestamp: string;                // ISO 8601 — event occurrence time
}
```

**PHI Logging Guidelines:**

* **Allowed:** `eligibility_check_id`, `patient_id` (UUID only — no name/DOB), `parsing_confidence`, `service_types_parsed`, `organization_id`
* **Prohibited:** copay/coinsurance/deductible amounts, OOP max values, raw EB segments, subscriber identifiers
* **Retention:** Event logged via `publishEvent()`; no benefit dollar amounts in application logs or edge function stdout (`createLogger` sanitization required)

**Consumer Actions:**

1. **PM-48 (Patient Cost Estimation):** Trigger refresh of patient responsibility estimates for affected appointments
2. **PM-07 (Charge Capture):** Refresh copay/deductible defaults shown in charge entry form for the patient

**Implementation Note:**

* Published via `publishEvent()` from `@/platform/events` after `pm-parse-271-benefits` edge function completes successful parsing
* Channel `pm_events` (already declared for `pm_eligibility_verified`)
* Service-role edge function MUST scope all DB writes by `organization_id` before publishing (defense-in-depth per PM-02-EN-02 FR-3.1)

***

### PM-01-EN-01: Patient Merge Events

**Status:** 📋 Specification — implementation pending
**Spec Reference:** [PM-01-EN-01-patient-merge-workflow.md](../../../specs/pm/specs/PM-01-EN-01-patient-merge-workflow.md)
**Integration Reference:** [PM-01-EN-01-patient-merge-workflow-INTEGRATION.md](./patient-merge-workflow-integration.md)

#### Event: `pm_patient_merged`

**Channel:** `pm_events`
**Publisher:** PM (Practice Management) — `pm_merge_patients()` SECURITY DEFINER function (PM-01-EN-01)
**Subscribers:** CL (chart cache invalidation), PM-08 (claims grouping cache), CE-29 (lead↔patient mapping), PF-71 (patient identity boundary)
**Trigger:** Successful commit of `pm_merge_patients()` after all PM/CL FK re-points and audit row write.
**Status:** 📋 Specification
**Schema Version:** 1

**Payload Schema:**

```typescript theme={null}
interface PatientMergedPayload {
  event_type: 'pm_patient_merged';
  schema_version: 1;
  organization_id: string;        // UUID — tenant isolation
  survivor_patient_id: string;    // UUID — winning pm_patients.id
  merged_patient_id: string;      // UUID — soft-deleted pm_patients.id
  merge_log_id: string;           // UUID — pm_patient_merge_log.id (idempotency key)
  occurred_at: string;            // ISO 8601 — commit time of pm_merge_patients()
}
```

**PHI Logging Guidelines:**

* **Allowed:** all payload fields above (UUIDs and timestamp only)
* **Prohibited:** `merge_reason` body, demographics, MRN, any chart data
* **Retention:** Event row retained in `fw_workflow_events`; PF-44 audit row retained per HIPAA §164.312(b)

**Delivery Semantics:**

* **Idempotency key:** `merge_log_id`
* **Delivery:** at-least-once
* **Ordering:** per `survivor_patient_id`
* **Undo:** v1 publishes **no** `pm_patient_merge_undone` event. Consumers MUST reconcile from `pm_patient_merge_log` (filter `rolled_back_at IS NOT NULL`) when maintaining long-lived projections.

**Consumer Actions:**

1. **CL:** Invalidate chart-by-patient caches keyed on `merged_patient_id`; subsequent reads will resolve to the survivor via the re-pointed `cl_patient_charts.patient_id`.
2. **PM-08 (Claims):** Drop in-memory groupings keyed on `merged_patient_id`.
3. **CE-29 (Lead Conversion):** Re-point lead↔patient mapping rows where applicable.
4. **PF-71 (Patient Identity Boundary):** Refresh identity caches.

**Implementation Notes:**

* Registered in `fw_workflow_events` via the PM-01-EN-01 migration (one row, schema\_version = 1, owning\_core = `pm`).
* Channel `pm_events` is already declared (PM-02 events).
* Published from inside the SECURITY DEFINER function; if the `fw_workflow_events` insert fails, the entire merge transaction aborts (no partial state).

***

### PM-50: AI Denial Prediction Events

**Status:** 📝 Planned
**Spec Reference:** [PM-50-ai-denial-prediction-prevention.md](../../../specs/pm/specs/PM-50-ai-denial-prediction-prevention.md)

#### Event 1: `pm.denial_prediction.created`

**Channel:** `pm_events`
**Publisher:** PM (Practice Management) — PM-50 / AI Denial Prediction service
**Subscribers:** None (available for future GR dashboards or analytics)
**Trigger:** After a denial risk prediction is generated and saved to `pm_denial_predictions`
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
interface DenialPredictionCreatedPayload {
  event_type: 'pm.denial_prediction.created';
  prediction_id: string;          // UUID — pm_denial_predictions.id
  claim_id: string;               // UUID — pm_claims.id (FK deferred until PM-08)
  risk_score: number;             // 0-100
  risk_level: 'low' | 'medium' | 'high';
  model_version: string;          // Model version used for prediction
  organization_id: string;        // Tenant isolation (UUID)
  site_id?: string;               // UUID — optional site scope
  timestamp: string;              // ISO 8601 — event occurrence time
}
```

**Storage:**

* Event table: `fw_domain_events` (via `publishEvent()` from `@/platform/events`)
* Retention: Standard event retention policy (see EVENT\_DELIVERY.md)

**PHI Logging Guidelines:**

* **Allowed:** `prediction_id`, `claim_id` (UUID only), `risk_score`, `risk_level`, `model_version`, `organization_id`
* **Prohibited:** No PHI; claim-level features are categorical/aggregate only
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs or edge function stdout

**Purpose:** Notify when a new denial prediction is created. Available for future integration with GR dashboards or analytics tracking.

**Implementation Note:**

* Register in `fw_workflow_events` table via seed migration
* Published via `publishEvent()` from `@/platform/events` after prediction record creation in `predict-denial-risk` edge function

***

#### Event 2: `pm.denial_prediction.outcome_recorded`

**Channel:** `pm_events`
**Publisher:** PM (Practice Management) — PM-50 / PM-29 Denial Management (via feedback loop)
**Subscribers:** PM-50 (retraining pipeline for model feedback)
**Trigger:** When `actual_outcome` field is updated on `pm_denial_predictions` (claim adjudication result recorded)
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
interface DenialPredictionOutcomeRecordedPayload {
  event_type: 'pm.denial_prediction.outcome_recorded';
  prediction_id: string;          // UUID — pm_denial_predictions.id
  claim_id: string;               // UUID — pm_claims.id
  actual_outcome: 'paid' | 'denied';
  actual_denial_reason?: string;  // Optional — denial reason code if denied
  prediction_correct: boolean;    // Whether prediction matched outcome
  organization_id: string;        // Tenant isolation (UUID)
  timestamp: string;              // ISO 8601 — event occurrence time
}
```

**Storage:**

* Event table: `fw_domain_events` (via `publishEvent()` from `@/platform/events`)
* Retention: Standard event retention policy (see EVENT\_DELIVERY.md)

**PHI Logging Guidelines:**

* **Allowed:** `prediction_id`, `claim_id` (UUID only), `actual_outcome`, `actual_denial_reason` (code only), `organization_id`
* **Prohibited:** No PHI; denial reason is code-level only (no narrative)
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs or edge function stdout

**Purpose:** Notify when actual claim outcome is recorded for model feedback. PM-50 retraining pipeline consumes this to improve prediction accuracy.

**Consumer Actions:**

1. **PM-50 Retraining:** Add outcome to training dataset for monthly model retraining
2. **Analytics:** Track prediction accuracy over time (precision/recall metrics)

**Implementation Note:**

* Register in `fw_workflow_events` table via seed migration
* Published via database trigger on `pm_denial_predictions` UPDATE when `actual_outcome` changes from NULL to non-NULL
* Alternative: Published via `publishEvent()` from PM-29 when denial outcome is recorded

***

### CL-09: cl\_lab\_order\_created

**Event:** `cl_lab_order_created`\
**Channel:** `cl_pm_events`\
**Publisher:** CL (Clinical & EHR) — CL-09\
**Subscribers:** PF-10 (Notifications), FW (Workflow Automation)\
**Status:** 📝 Planned\
**Spec Reference:** [CL-09 – Lab & Diagnostic Orders & Results](../../../specs/cl/specs/CL-09-lab-diagnostic-orders-results.md)\
**Integration Doc:** [CL-09-lab-diagnostic-orders-results-INTEGRATION.md](./lab-diagnostic-orders-results-integration.md)\
**Owner:** CL team.

**Purpose:** Notify when a lab order transitions from `draft` to `ordered` so downstream systems can track pending orders and trigger workflow automations.

**Trigger Conditions:** UPDATE on `cl_orders` WHERE `NEW.status = 'ordered'` AND `OLD.status = 'draft'`.

**Payload Schema:**

| Field                  | Type              | Required | Description                          |
| ---------------------- | ----------------- | -------- | ------------------------------------ |
| `event_type`           | string            | Yes      | Must equal `"cl_lab_order_created"`. |
| `organization_id`      | uuid              | Yes      | Tenant isolation.                    |
| `timestamp`            | string (ISO 8601) | Yes      | Event occurrence time.               |
| `site_id`              | uuid              | Optional | If site-scoped.                      |
| `user_id`              | uuid              | Yes      | Ordering clinician.                  |
| `correlation_id`       | string (uuid)     | Optional | For audit/chain.                     |
| `order_id`             | uuid              | Yes      | Order record ID.                     |
| `chart_id`             | uuid              | Yes      | Patient chart ID.                    |
| `ordering_provider_id` | uuid              | Yes      | Ordering provider ID.                |
| `loinc_code`           | string            | Yes      | LOINC code for the ordered test.     |
| `priority`             | string            | Yes      | `routine` or `stat`.                 |
| `lab_id`               | uuid              | Optional | Reference lab ID if external.        |

**PHI Logging Guidelines:**

* **Allowed:** `order_id`, `chart_id`, `ordering_provider_id`, `loinc_code`, `priority`, `lab_id`, `organization_id`
* **Prohibited:** Patient names, DOB, SSN, result values, diagnosis information
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs or edge function stdout

**Implementation:** Not yet implemented. Published via `publishEvent()` from `@/platform/events`.

***

### CL-09: cl\_lab\_result\_received

**Event:** `cl_lab_result_received`\
**Channel:** `cl_pm_events`\
**Publisher:** CL (Clinical & EHR) — CL-09 / External Lab Interface\
**Subscribers:** CL-08 (Clinical Decision Support — abnormal result alert via `evaluateCdsRules()`), PF-10 (Notifications)\
**Status:** 📝 Planned\
**Spec Reference:** [CL-09 – Lab & Diagnostic Orders & Results](../../../specs/cl/specs/CL-09-lab-diagnostic-orders-results.md)\
**Integration Doc:** [CL-09-lab-diagnostic-orders-results-INTEGRATION.md](./lab-diagnostic-orders-results-integration.md)\
**Owner:** CL team.

**Purpose:** Notify when a lab result is ingested (via HL7v2/FHIR interface or manual entry) so CL-08 CDS can evaluate for abnormal result alerts and notifications can be sent to the ordering provider.

**Trigger Conditions:** INSERT on `cl_order_results` (result ingested from external interface or manually entered); order status transitions to `resulted`.

**Payload Schema:**

| Field             | Type              | Required | Description                                        |
| ----------------- | ----------------- | -------- | -------------------------------------------------- |
| `event_type`      | string            | Yes      | Must equal `"cl_lab_result_received"`.             |
| `organization_id` | uuid              | Yes      | Tenant isolation.                                  |
| `timestamp`       | string (ISO 8601) | Yes      | Event occurrence time.                             |
| `site_id`         | uuid              | Optional | If site-scoped.                                    |
| `user_id`         | uuid              | Optional | Null for interface-ingested results.               |
| `correlation_id`  | string (uuid)     | Optional | For audit/chain.                                   |
| `order_id`        | uuid              | Yes      | Parent order ID.                                   |
| `result_id`       | uuid              | Yes      | Result record ID.                                  |
| `chart_id`        | uuid              | Yes      | Patient chart ID.                                  |
| `loinc_code`      | string            | Yes      | LOINC code for the resulted test.                  |
| `abnormal_flag`   | string            | Optional | `N`, `L`, `H`, `LL`, `HH`, `A` per HL7 Table 0078. |
| `source`          | string            | Yes      | `interface` or `manual`.                           |

**PHI Logging Guidelines:**

* **Allowed:** `order_id`, `result_id`, `chart_id`, `loinc_code`, `abnormal_flag`, `source`, `organization_id`
* **Prohibited:** Patient names, DOB, SSN, actual result values (`result_value`, `result_value_numeric`), reference ranges
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs or edge function stdout

**Consumer Actions:**

| Consumer              | Action                                                   | Status     |
| --------------------- | -------------------------------------------------------- | ---------- |
| CL-08 (CDS)           | Evaluate `evaluateCdsRules()` for abnormal result alerts | 📝 Planned |
| PF-10 (Notifications) | Notify ordering provider of new result                   | 📝 Planned |
| Event Consumer        | Log to `pf_audit_logs`                                   | 📝 Planned |

**Implementation:** Not yet implemented. Published via `publishEvent()` from `@/platform/events` or from the `cl-lab-result-ingestion` edge function for interface-ingested results.

***

### CL-09: cl\_lab\_result\_reviewed

**Event:** `cl_lab_result_reviewed`\
**Channel:** `cl_pm_events`\
**Publisher:** CL (Clinical & EHR) — CL-09\
**Subscribers:** PF-10 (Notifications), PF-04 (Audit)\
**Status:** 📝 Planned\
**Spec Reference:** [CL-09 – Lab & Diagnostic Orders & Results](../../../specs/cl/specs/CL-09-lab-diagnostic-orders-results.md)\
**Integration Doc:** [CL-09-lab-diagnostic-orders-results-INTEGRATION.md](./lab-diagnostic-orders-results-integration.md)\
**Owner:** CL team.

**Purpose:** Notify when a clinician signs off on (reviews) a lab result, completing the result review workflow. This creates an audit trail and can trigger downstream notifications.

**Trigger Conditions:** UPDATE on `cl_order_results` WHERE `NEW.reviewed_by IS NOT NULL` AND `OLD.reviewed_by IS NULL`; order status transitions to `reviewed`.

**Payload Schema:**

| Field             | Type              | Required | Description                            |
| ----------------- | ----------------- | -------- | -------------------------------------- |
| `event_type`      | string            | Yes      | Must equal `"cl_lab_result_reviewed"`. |
| `organization_id` | uuid              | Yes      | Tenant isolation.                      |
| `timestamp`       | string (ISO 8601) | Yes      | Event occurrence time.                 |
| `site_id`         | uuid              | Optional | If site-scoped.                        |
| `user_id`         | uuid              | Yes      | Reviewing clinician.                   |
| `correlation_id`  | string (uuid)     | Optional | For audit/chain.                       |
| `order_id`        | uuid              | Yes      | Parent order ID.                       |
| `result_id`       | uuid              | Yes      | Result record ID.                      |
| `chart_id`        | uuid              | Yes      | Patient chart ID.                      |
| `reviewed_by`     | uuid              | Yes      | Clinician who reviewed/signed off.     |

**PHI Logging Guidelines:**

* **Allowed:** `order_id`, `result_id`, `chart_id`, `reviewed_by`, `organization_id`
* **Prohibited:** Patient names, DOB, SSN, actual result values, clinical notes
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs or edge function stdout

**Implementation:** Not yet implemented. Published via `publishEvent()` from `@/platform/events`.

***

## Related Documentation

* [Platform Integration Layers](./PLATFORM_INTEGRATION_LAYERS.md) - Platform layer integrations
* [API Contracts](./API_CONTRACTS.md) - API-based integrations
* [IT Integration Contracts](./IT_INTEGRATION_CONTRACTS.md) - IT module integration contracts
* [Integration Examples](../patterns/INTEGRATION_EXAMPLES.md) - Code examples
* [Constitution](../../../constitution.md) - Engineering guardrails

***

## PF-63: Teams Channel Notification Dispatch

**Event:** `teams_channel_notification_dispatched`\
**Publisher:** PF (Platform Foundation) — `event-consumer` edge function\
**Subscribers:** `entra-teams-notify` edge function\
**Status:** ✅ Complete\
**Implemented:** 2026-02-21

**Description:**
When any domain event is consumed by `event-consumer`, it checks `pf_teams_notification_config` for matching rules. If active rules exist for the event type and organization, it dispatches messages to the configured Teams channels via `entra-teams-notify`.

**Routing Mechanism:**

* Table: `pf_teams_notification_config`
* Match criteria: `organization_id` + `event_name` + `is_active = true`
* Each matching rule triggers a separate call to `entra-teams-notify`

**Payload Schema:**

```typescript theme={null}
{
  event_type: string;          // The original domain event name
  payload: {
    organization_id: uuid;     // Required for tenant isolation
    [key: string]: unknown;    // Event-specific data
  };
}
```

**Dispatch Payload (to entra-teams-notify):**

```typescript theme={null}
{
  organization_id: uuid;
  team_id: string;             // From notification config rule
  channel_id: string;          // From notification config rule
  message_type: string;        // Original event_type
  payload: Record<string, unknown>;
  message_template?: string;   // Optional custom template from rule
}
```

**Supported Event Types (built-in message templates):**

* `hr_employee_hired` — New hire announcement
* `credential_expiring` — Credential expiry warning
* `form_submitted` — Form submission notification
* `leave_approved` — Leave approval notification
* `rh_resident_admitted` — New resident admission (canonical; replaces `resident_admitted`)

**Security:**

* Service-role authentication for dispatch calls
* HTML escaping on all interpolated template values
* Organization access verified via `verifyOrgAccess()`

***

## CL-12: Care Coordination & Transitions Events

### Event: `referral_accepted`

**Channel:** `cl_pm_events`\
**Publisher:** PM (Practice Management) — PM-06\
**Subscribers:** CL-12 (Care Coordination)\
**Status:** ✅ Implemented (Consumer in event-consumer edge function)
**Spec Reference:** [CL-12](../../../specs/cl/specs/CL-12-care-coordination-transitions.md), [CL-PM-REFERRALS](./CL-PM-REFERRALS.md)

**Purpose:** When a referral is accepted (PM-06 status → `admitted`), CL-12 creates a `cl_transitions` record (type = `referral`), links `referral_id`, and triggers discharge checklist / medication reconciliation as applicable.

**Trigger Conditions:** UPDATE on `pm_referrals` WHERE `NEW.status = 'admitted'` AND `OLD.status != 'admitted'`.

**Payload Schema:**

| Field                | Type              | Required | Description                         |
| -------------------- | ----------------- | -------- | ----------------------------------- |
| `event_type`         | string            | Yes      | Must equal `"referral_accepted"`.   |
| `organization_id`    | uuid              | Yes      | Tenant isolation.                   |
| `timestamp`          | string (ISO 8601) | Yes      | Event occurrence time.              |
| `user_id`            | uuid              | Yes      | User who accepted the referral.     |
| `correlation_id`     | string (uuid)     | Optional | For audit/chain.                    |
| `referral_id`        | uuid              | Yes      | PM-06 referral record ID.           |
| `patient_id`         | uuid              | Yes      | Patient ID.                         |
| `referral_direction` | string            | Yes      | `inbound` or `outbound`.            |
| `from_facility`      | string            | Optional | Originating facility.               |
| `to_facility`        | string            | Optional | Destination facility.               |
| `from_level_of_care` | string            | Optional | Source LOC.                         |
| `to_level_of_care`   | string            | Optional | Destination LOC.                    |
| `referral_reason`    | string            | Yes      | Reason for referral.                |
| `urgency`            | string            | Yes      | `routine`, `urgent`, or `emergent`. |

**PHI Logging Guidelines:**

* **Allowed:** `referral_id`, `patient_id`, `organization_id`, `urgency`, `referral_direction`
* **Prohibited:** Patient names, DOB, SSN, clinical notes, diagnosis codes
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs or edge function stdout

**Consumer Actions (CL-12):**

1. Create `cl_transitions` record with `transition_type = 'referral'` and `referral_id`
2. If outbound: trigger discharge checklist creation
3. Trigger medication reconciliation (CL-05)
4. Generate C-CDA transition summary (CL-16, when available)

***

### Event: `transition_completed`

**Channel:** `cl_pm_events`\
**Publisher:** CL (Clinical & EHR) — CL-12\
**Subscribers:** PM-06 (Referral Management)\
**Status:** ✅ Implemented (Published by useCompleteChecklist hook)
**Spec Reference:** [CL-12](../../../specs/cl/specs/CL-12-care-coordination-transitions.md), [CL-PM-REFERRALS](./CL-PM-REFERRALS.md)

**Purpose:** Published when a discharge checklist is completed for a transition that has a linked `referral_id`. PM-06 consumes this to update the referral status to `completed`.

**Trigger Conditions:** UPDATE on `cl_discharge_checklists` WHERE `NEW.overall_status = 'completed'` AND `OLD.overall_status != 'completed'` AND parent `cl_transitions.referral_id IS NOT NULL`.

**Payload Schema:**

| Field             | Type              | Required | Description                               |
| ----------------- | ----------------- | -------- | ----------------------------------------- |
| `event_type`      | string            | Yes      | Must equal `"transition_completed"`.      |
| `organization_id` | uuid              | Yes      | Tenant isolation.                         |
| `timestamp`       | string (ISO 8601) | Yes      | Event occurrence time.                    |
| `user_id`         | uuid              | Yes      | User who completed the checklist.         |
| `correlation_id`  | string (uuid)     | Optional | For audit/chain.                          |
| `transition_id`   | uuid              | Yes      | CL-12 transition record ID.               |
| `chart_id`        | uuid              | Yes      | Patient chart ID.                         |
| `referral_id`     | uuid              | Yes      | Linked PM-06 referral ID.                 |
| `transition_type` | string            | Yes      | `discharge`, `transfer`, `referral`, etc. |
| `checklist_id`    | uuid              | Yes      | Completed discharge checklist ID.         |

**PHI Logging Guidelines:**

* **Allowed:** `transition_id`, `chart_id`, `referral_id`, `checklist_id`, `organization_id`, `transition_type`
* **Prohibited:** Patient names, DOB, SSN, checklist item notes, clinical details
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs or edge function stdout

**Consumer Actions (PM-06):**

1. Update `pm_referrals` status to `completed` where `id = referral_id`

***

## CL-15: Clinical Reporting & Quality Measures Events

### Event: `cl_incident_reported`

**Channel:** `cl_events`\
**Publisher:** CL (Clinical & EHR) — CL-15\
**Subscribers:** GR-03 (Compliance Tracking), GR-04 (Audit Management), GR-08 (Accreditation Management), PF-10 (Notifications)\
**Status:** ✅ Implemented\
**Spec Reference:** [CL-15](../../../specs/cl/specs/CL-15-clinical-reporting-quality-measures.md), [CL-15 Integration](./clinical-reporting-quality-measures-integration.md)

**Purpose:** Published when a clinical incident is formally reported to the state, indicating a regulatory reporting action. GR consumes this for compliance tracking, audit workflows, and accreditation evidence. PF-10 notifies compliance officers and administrators.

**Trigger Conditions:** UPDATE on `cl_incidents` WHERE `NEW.reported_to_state_at IS NOT NULL` AND `OLD.reported_to_state_at IS NULL`.

**Payload Schema:**

```typescript theme={null}
interface ClIncidentReportedPayload {
  incident_id: string;              // UUID of the reported incident
  organization_id: string;          // UUID of the organization
  chart_id: string | null;          // UUID of the patient chart, if applicable
  incident_type: string;            // 'death' | 'serious_injury' | 'abuse' | 'neglect' | 'elopement' | 'other'
  severity: string;                 // 'critical' | 'major' | 'moderate' | 'minor'
  reported_to_state_at: string;     // ISO timestamp when reported to state
  reporting_deadline: string;       // ISO timestamp of the regulatory deadline
  reported_by: string;              // UUID of the user who marked it as reported
  custom_fields: Record<string, unknown>;
}
```

**Consumer Actions:**

| Consumer                         | Action                                                                                                                                                           | Status        |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| GR-03 (Compliance Tracking)      | Invokes `gr-handle-incident-reported` edge function via `fw_domain_events` trigger; creates `gr_compliance_checks` row with `result: fail`, `check_type: ad_hoc` | ✅ Implemented |
| GR-04 (Audit Management)         | Initiate audit workflow for reportable incidents                                                                                                                 | ✅ Implemented |
| GR-08 (Accreditation Management) | Log incident as accreditation evidence (Joint Commission, CARF)                                                                                                  | ✅ Implemented |
| PF-10 (Notifications)            | Notify compliance officers and administrators                                                                                                                    | ✅ Implemented |

**PHI/PII Logging Guidelines:**

* **Safe to log:** `incident_id`, `organization_id`, `incident_type`, `severity`, `reported_by`
* **Log as flag only:** `chart_id` → log `has_chart_id: true/false`
* **Prohibited:** patient names, chart content, clinical details
* **`custom_fields`** must be sanitized to remove any PII/PHI before logging

**Idempotency:** Handled by FW-16 workflow engine via `event_name` + `payload_hash`.

***

<h2 id="cl-16-en-01-tefca-qhin-events">
  CL-16-EN-01: TEFCA/QHIN Connectivity Events (Planned) \\
</h2>

**Publisher:** CL (Clinical & EHR) — CL-16-EN-01\
**Status:** 📝 Planned\
**Spec Reference:** [CL-16-EN-01](../../../specs/cl/specs/CL-16-EN-01-tefca-qhin-connectivity.md)\
**Integration Doc:** [CL-16-EN-01-tefca-qhin-connectivity-INTEGRATION.md](./tefca-qhin-connectivity-integration.md)\
**Ownership:** CL-16-EN-01 owns event production and payload versioning.

**Payload constraints (all TEFCA events):**

* Required identifiers: `event_id` (UUID), `organization_id`, `patient_id` (nullable when unresolved), `correlation_id`, `status`.
* Identifier-only payloads; no PHI payload bodies.
* `event_id` is required for idempotency and retry deduplication across at-least-once delivery.

<h3 id="cl-tefca-query-submitted">
  Event: `cl_tefca_query_submitted` \\
</h3>

**Channel:** `cl_pm_events`\
**Publisher:** CL-16-EN-01\
**Consumers:** PF-04 audit, operations analytics\
**Status:** 📝 Planned

**Purpose:** Record submission of a TEFCA/QHIN patient query with traceable correlation.

**Payload minimums:** `event_id`, `organization_id`, `patient_id`, `correlation_id`, `status = 'submitted'`, requester context.
`event_id` MUST be a UUID string and is required for idempotency/retry semantics.

<h3 id="cl-tefca-exchange-completed">
  Event: `cl_tefca_exchange_completed` \\
</h3>

**Channel:** `cl_pm_events`\
**Publisher:** CL-16-EN-01\
**Consumers:** PF-04 audit, CL-12 downstream exchange consumers\
**Status:** 📝 Planned

**Purpose:** Record successful TEFCA/QHIN exchange completion for downstream retrieval/processing.

**Payload minimums:** `event_id`, `organization_id`, `patient_id`, `correlation_id`, `status = 'completed'`, exchange log reference.
`event_id` MUST be a UUID string and is required for idempotency/retry semantics.

<h3 id="cl-tefca-exchange-blocked">
  Event: `cl_tefca_exchange_blocked` \\
</h3>

**Channel:** `cl_pm_events`\
**Publisher:** CL-16-EN-01\
**Consumers:** PF-04 audit, compliance workflows\
**Status:** 📝 Planned

**Purpose:** Record policy/consent-blocked TEFCA exchange attempts (fail-closed path).

**Payload minimums:** `event_id`, `organization_id`, `patient_id`, `correlation_id`, `status = 'blocked'`, policy/consent block reason code.
`event_id` MUST be a UUID string and is required for idempotency/retry semantics.

***

## CL-16: FHIR Interoperability & Data Exchange Events

### Event: `cl_fhir_bundle_exported`

**Channel:** `cl_pm_events`\
**Publisher:** CL (Clinical & EHR) — CL-16\
**Subscribers:** PF-04 (Audit), PF-10 (Notifications)\
**Status:** 🟡 In Progress (Phase 1)\
**Spec Reference:** [CL-16](../../../specs/cl/specs/CL-16-fhir-interoperability-data-exchange.md)

**Purpose:** Published when a FHIR `$patient-everything` bundle or bulk export is completed. Triggers audit logging and optional notifications to compliance staff.

**Trigger Conditions:** Successful completion of `patient-everything` action in the `fhir-r4` edge function.

**Payload Schema:**

| Field               | Type              | Required | Description                                                              |
| ------------------- | ----------------- | -------- | ------------------------------------------------------------------------ |
| `event_type`        | string            | Yes      | Must equal `"cl_fhir_bundle_exported"`.                                  |
| `organization_id`   | uuid              | Yes      | Tenant isolation.                                                        |
| `timestamp`         | string (ISO 8601) | Yes      | Event occurrence time.                                                   |
| `user_id`           | uuid              | Yes      | User who triggered the export.                                           |
| `correlation_id`    | string (uuid)     | Optional | For audit/chain.                                                         |
| `chart_id`          | uuid              | Yes      | Patient chart ID.                                                        |
| `exchange_log_id`   | uuid              | Yes      | `cl_data_exchange_log` record ID.                                        |
| `exchange_type`     | string            | Yes      | `fhir_api`, `bulk_export`, or `patient_access`.                          |
| `resource_types`    | string\[]         | Yes      | FHIR resource types included (e.g., `["Patient","Condition"]`).          |
| `record_count`      | number            | Yes      | Total resources in the bundle.                                           |
| `has_part2_consent` | boolean           | Yes      | Whether Part 2 consent was active (determines if SUD data was included). |

**PHI Logging Guidelines:**

* **Allowed:** `chart_id`, `exchange_log_id`, `organization_id`, `user_id`, `exchange_type`, `resource_types`, `record_count`, `has_part2_consent`
* **Prohibited:** Patient names, DOB, SSN, diagnosis codes, medication names, clinical content
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs or edge function stdout

**Consumer Actions:**

1. **PF-04 (Audit):** Log export event to `pf_audit_logs` with exchange details
2. **PF-10 (Notifications):** Optionally notify compliance officer for bulk/patient-access exports

**Idempotency:** Unique on `(correlation_id, event_type)`. Consumers should deduplicate by `exchange_log_id`.

***

### Event: `cl_ccda_document_sent`

**Channel:** `cl_pm_events`\
**Publisher:** CL (Clinical & EHR) — CL-16\
**Subscribers:** PF-04 (Audit), GR (Governance & Compliance)\
**Status:** 📝 Planned (Phase 2)\
**Spec Reference:** [CL-16](../../../specs/cl/specs/CL-16-fhir-interoperability-data-exchange.md)

**Purpose:** Published when a C-CDA 2.1 document is sent to an external partner (e.g., Arizona Contexture HIE, DirectTrust recipient). Triggers audit logging and compliance tracking.

**Trigger Conditions:** Successful transmission of C-CDA document to external recipient.

**Payload Schema:**

| Field                          | Type              | Required | Description                                             |
| ------------------------------ | ----------------- | -------- | ------------------------------------------------------- |
| `event_type`                   | string            | Yes      | Must equal `"cl_ccda_document_sent"`.                   |
| `organization_id`              | uuid              | Yes      | Tenant isolation.                                       |
| `timestamp`                    | string (ISO 8601) | Yes      | Event occurrence time.                                  |
| `user_id`                      | uuid              | Yes      | User or service account that initiated the send.        |
| `correlation_id`               | string (uuid)     | Optional | For audit/chain.                                        |
| `chart_id`                     | uuid              | Yes      | Patient chart ID.                                       |
| `exchange_log_id`              | uuid              | Yes      | `cl_data_exchange_log` record ID.                       |
| `document_type`                | string            | Yes      | `CCD`, `discharge_summary`, or `referral_note`.         |
| `partner_id`                   | uuid              | Optional | Recipient organization/partner ID.                      |
| `partner_name`                 | string            | Optional | Recipient name (e.g., "Arizona Contexture").            |
| `has_part2_consent`            | boolean           | Yes      | Whether Part 2 consent was active.                      |
| `redisclosure_notice_included` | boolean           | Yes      | Whether 42 CFR Part 2 redisclosure notice was attached. |

**PHI Logging Guidelines:**

* **Allowed:** `chart_id`, `exchange_log_id`, `organization_id`, `user_id`, `document_type`, `partner_id`, `partner_name`, `has_part2_consent`, `redisclosure_notice_included`
* **Prohibited:** Patient names, DOB, SSN, clinical content, diagnosis codes
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs

**Consumer Actions:**

1. **PF-04 (Audit):** Log send event with partner details and document type
2. **GR (Compliance):** Track C-CDA exchanges for regulatory reporting; verify redisclosure notice compliance

**Idempotency:** Unique on `(correlation_id, event_type)`. Consumers deduplicate by `exchange_log_id`.

***

### Event: `cl_ccda_document_received`

**Channel:** `cl_pm_events`\
**Publisher:** CL (Clinical & EHR) — CL-16\
**Subscribers:** CL-01 (Patient Chart), PF-10 (Notifications)\
**Status:** 📝 Planned (Phase 2)\
**Spec Reference:** [CL-16](../../../specs/cl/specs/CL-16-fhir-interoperability-data-exchange.md)

**Purpose:** Published when a C-CDA 2.1 document is received from an external partner (e.g., HIE, DirectTrust sender). Triggers chart update and notifications to the assigned clinician.

**Trigger Conditions:** Successful ingestion and parsing of inbound C-CDA document.

**Payload Schema:**

| Field                      | Type              | Required | Description                                                                            |
| -------------------------- | ----------------- | -------- | -------------------------------------------------------------------------------------- |
| `event_type`               | string            | Yes      | Must equal `"cl_ccda_document_received"`.                                              |
| `organization_id`          | uuid              | Yes      | Tenant isolation.                                                                      |
| `timestamp`                | string (ISO 8601) | Yes      | Event occurrence time.                                                                 |
| `user_id`                  | uuid              | Optional | Service account or user who processed the document.                                    |
| `correlation_id`           | string (uuid)     | Optional | For audit/chain.                                                                       |
| `chart_id`                 | uuid              | Yes      | Matched patient chart ID (after MPI resolution).                                       |
| `exchange_log_id`          | uuid              | Yes      | `cl_data_exchange_log` record ID.                                                      |
| `document_type`            | string            | Yes      | `CCD`, `discharge_summary`, `referral_note`, or `adt_notification`.                    |
| `partner_id`               | uuid              | Optional | Sending organization/partner ID.                                                       |
| `partner_name`             | string            | Optional | Sender name.                                                                           |
| `resource_types_extracted` | string\[]         | Yes      | FHIR resource types parsed from the C-CDA (e.g., `["Condition","MedicationRequest"]`). |
| `record_count`             | number            | Yes      | Number of discrete data elements extracted.                                            |
| `reconciliation_needed`    | boolean           | Yes      | Whether new data conflicts with existing chart data.                                   |

**PHI Logging Guidelines:**

* **Allowed:** `chart_id`, `exchange_log_id`, `organization_id`, `document_type`, `partner_id`, `partner_name`, `resource_types_extracted`, `record_count`, `reconciliation_needed`
* **Prohibited:** Patient names, DOB, SSN, extracted clinical content, diagnosis codes, medication names
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs

**Consumer Actions:**

1. **CL-01 (Chart):** Flag chart for reconciliation review if `reconciliation_needed = true`; store document reference in `cl_patient_chart_documents`
2. **PF-10 (Notifications):** Notify assigned clinician that new external data is available for review

**Idempotency:** Unique on `(correlation_id, event_type)`. Consumers deduplicate by `exchange_log_id`.

***

## PM-13: Telehealth Integration Events

### Event: `telehealth_session_started`

**Channel:** `cl_pm_events`\
**Publisher:** PM-13 (Telehealth Integration)\
**Status:** ✅ Implemented\
**Last Verified:** 2026-02-23

**Purpose:** Published when a telehealth session transitions to `active` status. Provides encounter context for modifier selection and clinical documentation.

**Trigger Conditions:** `pm_telehealth_sessions.session_status` updated from `scheduled` or `waiting` to `active`.

**Payload Schema:**

| Field                 | Type              | Required | Description                                                           |
| --------------------- | ----------------- | -------- | --------------------------------------------------------------------- |
| `event_type`          | string            | Yes      | Must equal `"telehealth_session_started"`.                            |
| `organization_id`     | uuid              | Yes      | Tenant isolation.                                                     |
| `timestamp`           | string (ISO 8601) | Yes      | Event occurrence time.                                                |
| `user_id`             | uuid              | Yes      | Provider who started the session.                                     |
| `correlation_id`      | string (uuid)     | Optional | For audit/chain.                                                      |
| `session_id`          | uuid              | Yes      | `pm_telehealth_sessions.id`.                                          |
| `appointment_id`      | uuid              | Yes      | Linked `pm_appointments.id`.                                          |
| `encounter_id`        | uuid              | Optional | Linked encounter ID, if created.                                      |
| `telehealth_modality` | string            | Yes      | `audio_video`, `audio_only`, `store_forward`, or `remote_monitoring`. |
| `platform`            | string            | Yes      | Platform name (e.g., `Zoom Healthcare`, `Doxy.me`, `stub`).           |

**PHI Logging Guidelines:**

* **Allowed:** `session_id`, `appointment_id`, `encounter_id`, `organization_id`, `telehealth_modality`, `platform`, `user_id`
* **Prohibited:** Patient names, DOB, SSN, session URLs, join links, recording URLs
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs

**Consumer Actions:**

1. **FW-16 (Workflow):** Trigger automation rules on session start (e.g., notify care team)
2. **PF-10 (Notifications):** Send session-started notification to relevant staff

**Idempotency:** Unique on `(correlation_id, event_type)`. Consumers deduplicate by `session_id`.

***

### Event: `telehealth_session_completed`

**Channel:** `cl_pm_events`\
**Publisher:** PM-13 (Telehealth Integration)\
**Status:** ✅ Implemented\
**Last Verified:** 2026-02-23

**Purpose:** Published when a telehealth session transitions to `completed` status. Provides session metadata for PM-07 auto-modifier/POS assignment and CL-04 clinical documentation pre-fill.

**Trigger Conditions:** `pm_telehealth_sessions.session_status` updated to `completed`.

**Payload Schema:**

| Field                 | Type              | Required | Description                                                            |
| --------------------- | ----------------- | -------- | ---------------------------------------------------------------------- |
| `event_type`          | string            | Yes      | Must equal `"telehealth_session_completed"`.                           |
| `organization_id`     | uuid              | Yes      | Tenant isolation.                                                      |
| `timestamp`           | string (ISO 8601) | Yes      | Event occurrence time.                                                 |
| `user_id`             | uuid              | Yes      | Provider who ended the session.                                        |
| `correlation_id`      | string (uuid)     | Optional | For audit/chain.                                                       |
| `session_id`          | uuid              | Yes      | `pm_telehealth_sessions.id`.                                           |
| `appointment_id`      | uuid              | Yes      | Linked `pm_appointments.id`.                                           |
| `encounter_id`        | uuid              | Optional | Linked encounter ID.                                                   |
| `telehealth_modality` | string            | Yes      | `audio_video`, `audio_only`, `store_forward`, or `remote_monitoring`.  |
| `is_audio_only`       | boolean           | Yes      | Deprecated flag for backward compat with PM-07 modifier-logic.ts.      |
| `patient_location`    | string            | Optional | Patient location (e.g., `home`, `office`). Drives POS code (10 vs 02). |
| `provider_location`   | string            | Optional | Provider location.                                                     |
| `duration_minutes`    | number            | Optional | Session duration in minutes.                                           |

**PHI Logging Guidelines:**

* **Allowed:** `session_id`, `appointment_id`, `encounter_id`, `organization_id`, `telehealth_modality`, `is_audio_only`, `duration_minutes`, `user_id`
* **Prohibited:** Patient names, DOB, SSN, session URLs, recording URLs, patient\_location (may reveal home address)
* **Masking:** `patient_location` logged as presence flag (`has_patient_location: true/false`), not raw value
* **Retention:** Event logged to `pf_audit_logs`; no PHI in application logs

**Consumer Actions:**

1. **PM-07 (Charge Capture):** Apply telehealth modifiers (95/FQ/GQ) and POS (02/10) based on `telehealth_modality` and `patient_location` when `clinical_note_finalized` fires
2. **FW-16 (Workflow):** Trigger post-session automation (e.g., satisfaction survey, follow-up scheduling)
3. **CL-04 (Progress Notes):** Pre-fill telehealth fields (`is_telehealth`, `telehealth_modality`, `patient_location`, `provider_location`) on the clinical note

**Idempotency:** Unique on `(correlation_id, event_type)`. Consumers deduplicate by `session_id`.

***

**Next Review:** 2026-03-03 (Quarterly)

***

### PM-15: Clearinghouse Integration Events

**Status:** 📝 Planned
**Implemented:** TBD
**Spec Reference:** PM-15 (Clearinghouse Integration)

#### Event 1: `clearinghouse_batch_submitted`

**Publisher:** PM (Practice Management) — PM-15 Clearinghouse
**Subscribers:** PM-08 (Claims), PF-10 (Notifications), PM-11 (RCM Dashboard)

**Payload Schema:**

```typescript theme={null}
interface PmClearinghouseBatchSubmittedPayload {
  batch_id: string;              // UUID of the submitted batch
  clearinghouse_id: string;      // UUID of the clearinghouse config
  transaction_type: string;      // e.g., '837p', '837i'
  file_name: string;             // Name of the submitted file
  record_count: number;          // Number of records (claims) in batch
  submitted_at: string;          // ISO timestamp of submission
  organization_id: string;       // UUID of the organization
  user_id: string;               // UUID of user who triggered submission
}
```

**Purpose:** Notify downstream systems that a batch has been successfully transmitted to the clearinghouse.

**PHI Logging Guidelines:**

* **Allowed:** `batch_id`, `clearinghouse_id`, `transaction_type`, `record_count`, `organization_id`, `user_id`
* **Prohibited:** `file_name` (if it contains patient names/MRNs)
* **Masking:** Log `file_name` only if guaranteed safe (e.g., `BATCH_20260223_001.x12`); otherwise hash or redact
* **Retention:** Logged to `pf_audit_logs`

**Consumer Actions:**

1. **PM-08 (Claims):** Update claim status to `submitted` for all claims in the batch
2. **PM-11 (RCM Dashboard):** Increment submission metrics
3. **PF-10 (Notifications):** Notify billing admin of successful submission

#### Event 2: `clearinghouse_batch_error`

**Publisher:** PM (Practice Management) — PM-15 Clearinghouse
**Subscribers:** PM-08 (Claims), PF-10 (Notifications)

**Payload Schema:**

```typescript theme={null}
interface PmClearinghouseBatchErrorPayload {
  batch_id: string;              // UUID of the failed batch
  clearinghouse_id: string;      // UUID of the clearinghouse config
  transaction_type: string;      // e.g., '837p'
  error_code: string;            // Functional error code (e.g., 'AUTH_FAILED', 'SCHEMA_INVALID')
  error_message: string;         // Human-readable error
  organization_id: string;       // UUID of the organization
  timestamp: string;             // ISO timestamp of error
}
```

**Purpose:** Notify that a batch submission failed (e.g., connectivity error, 999 rejection).

**PHI Logging Guidelines:**

* **Allowed:** `batch_id`, `clearinghouse_id`, `transaction_type`, `error_code`, `organization_id`
* **Prohibited:** `error_message` (if it contains patient identifiers from a rejection)
* **Masking:** Sanitize `error_message` to remove potential PHI before logging
* **Retention:** Logged to `pf_audit_logs`

**Consumer Actions:**

1. **PM-08 (Claims):** Update claim status to `error` / `draft` (returned for correction)
2. **PF-10 (Notifications):** Alert billing admin of submission failure

#### Event 3: `clearinghouse_era_received`

**Publisher:** PM (Practice Management) — PM-15-P2 Clearinghouse Transport (Phase 2b)
**Subscribers:** PM-09 (Payment Posting & ERA), PM-29 (Denial Management)
**Channel:** `pm_events`
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
interface PmClearinghouseEraReceivedPayload {
  event_type: 'clearinghouse_era_received';
  event_id: string;              // UUID — Required for consumer deduplication (idempotency)
  correlation_id?: string;       // UUID — Optional correlation across related events
  era_file_id: string;           // UUID of the pm_era_files record created by parser
  organization_id: string;       // Tenant isolation (UUID)
  batch_id: string;              // UUID of the retrieval batch (pm_transaction_batches)
  claim_count: number;           // Number of CLP segments parsed
  total_paid: number;            // Sum of CLP-04 (total claim payment amount)
  timestamp: string;             // ISO 8601 — event occurrence time
}
```

**Purpose:** Notify downstream systems that an 835 ERA file has been retrieved from the clearinghouse and parsed. PM-09 uses this to trigger the payment posting pipeline; PM-29 uses CARC/RARC data from the parsed ERA for denial routing.

**PHI Logging Guidelines:**

* **Allowed:** `event_id`, `correlation_id`, `era_file_id`, `batch_id`, `claim_count`, `total_paid`, `organization_id`
* **Prohibited:** Storage object paths and individual CLP/SVC claim-level data
* **Masking:** If internal diagnostics require a storage lookup, log only the opaque `era_file_id`
* **Retention:** Logged to `pf_audit_logs`

**Consumer Actions:**

1. **PM-09 (Payment Posting & ERA):** Resolve storage location from `era_file_id`, then run payment posting pipeline — create `pm_payments` and `pm_payment_applications` from CLP/SVC data; persist CARC/RARC into `pm_transaction_log.error_codes`
2. **PM-29 (Denial Management):** Route CARC/RARC codes for denial intake and appeal workflow

#### Event 4: `clearinghouse_health_changed`

**Publisher:** PM (Practice Management) — PM-15-P2 Health Monitoring (Phase 2c)
**Subscribers:** PF-10 (Notifications)
**Channel:** `pm_events`
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
interface PmClearinghouseHealthChangedPayload {
  event_type: 'clearinghouse_health_changed';
  event_id: string;              // UUID — Required for consumer deduplication (idempotency)
  config_id: string;             // UUID of pm_clearinghouse_config
  organization_id: string;       // Tenant isolation (UUID)
  old_status: 'healthy' | 'degraded' | 'down' | 'unknown';
  new_status: 'healthy' | 'degraded' | 'down' | 'unknown';
  timestamp: string;             // ISO 8601 — event occurrence time
}
```

**Purpose:** Notify when clearinghouse connection health status changes. PF-10 fires alerts on transitions to `down` or `degraded`; recovery notifications are throttled (require 2 consecutive healthy checks before alerting on `healthy` transition).

**PHI Logging Guidelines:**

* **Allowed:** All fields (no PHI in health status events)
* **Prohibited:** None (event contains no patient data)
* **Retention:** Logged to `pf_audit_logs`

**Consumer Actions:**

1. **PF-10 (Notifications):** Alert billing admin on `down` or `degraded`; send recovery notification on `healthy` (throttled: 2 consecutive healthy checks required)

***

### PM-47: Managed Care Auth Tracking

**Status:** 📝 Planned
**Spec Reference:** [PM-47-managed-care-authorization-tracking.md](../../../specs/pm/specs/PM-47-managed-care-authorization-tracking.md)
**Integration Doc:** [PM-47-managed-care-authorization-tracking-INTEGRATION.md](./managed-care-authorization-tracking-integration.md)

#### Event: `pm_auth_expiring`

**Channel:** `pm_events`
**Publisher:** PM (Practice Management) — PM-47
**Subscribers:** PM (dashboard refresh), CL (clinical review preparation)
**Trigger:** Daily cron edge function checks authorizations approaching expiration thresholds
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
interface PmAuthExpiringPayload {
  event_type: 'pm_auth_expiring';
  event_id: string;              // UUID — Required for consumer deduplication (idempotency)
  correlation_id?: string;       // UUID — Optional correlation across related events
  organization_id: string;       // Tenant isolation (UUID)
  authorization_id: string;      // UUID — pm_managed_care_authorizations.id
  patient_id: string;            // UUID — patient identifier only; no PHI in payload
  payer_id: string;              // UUID — payer identifier
  expiration_date: string;       // ISO 8601 date
  days_remaining: number;        // Days until expiration
  service_type: string;          // e.g., 'residential', 'php', 'iop'
  timestamp: string;             // ISO 8601 — event occurrence time
}
```

**PHI Logging Guidelines:**

* **Allowed (PHI-safe identifiers):** `event_id`, `correlation_id`, `authorization_id`, `patient_id` (UUID only), `payer_id`, `expiration_date`, `days_remaining`, `service_type`, `organization_id`
* **Prohibited:** Patient name, DOB, auth details beyond what's in schema
* **Retention:** Event logged to `pf_audit_logs`
* **Logging Guidance:** Log only `event_id`, `correlation_id`, and non-PHI identifiers (e.g., `organization_id`, `authorization_id`, `payer_id`) in application logs; omit patient-identifiable data

**Consumer Actions:**

1. **PM (dashboard):** Refresh auth expiration dashboard counts
2. **CL (clinical review):** Pre-populate concurrent review task with auth context

***

#### Event: `pm_auth_validation_failed`

**Channel:** `pm_events`
**Publisher:** PM (Practice Management) — PM-47
**Subscribers:** PM-08 (claim submission gate)
**Trigger:** Pre-submission auth-to-claim validation detects authorization coverage gaps
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
interface PmAuthValidationFailedPayload {
  event_type: 'pm_auth_validation_failed';
  event_id: string;              // UUID — Required for consumer deduplication (idempotency)
  correlation_id?: string;       // UUID — Optional correlation across related events
  organization_id: string;       // Tenant isolation (UUID)
  claim_id: string;              // UUID — pm_claims.id
  failed_lines: Array<{
    line_number: number;
    reason_code: 'no_active_auth' | 'units_exceeded' | 'date_outside_auth';  // Machine-readable bounded enum
    message?: string;            // Optional human-readable message (localization-friendly)
  }>;
  timestamp: string;             // ISO 8601 — event occurrence time
}
```

**Validation Failure Reason Codes:**

* `no_active_auth` — No active authorization found for the service date and service type
* `units_exceeded` — Claim line units exceed remaining authorized units
* `date_outside_auth` — Service date falls outside the authorization's valid date range

**PHI Logging Guidelines:**

* **Allowed (PHI-safe identifiers):** `event_id`, `correlation_id`, `claim_id`, `line_number`, `reason_code`, `organization_id`
* **Prohibited:** Claim line service details, patient identifiers
* **Retention:** Event logged to `pf_audit_logs`
* **Logging Guidance:** Log only `event_id`, `correlation_id`, and non-PHI identifiers (e.g., `organization_id`, `claim_id`, `reason_code`) in application logs; omit patient-identifiable data and the optional `message` field

**Consumer Actions:**

1. **PM-08 (claim submission):** Block claim submission; display validation failure details to user

***

### CL-21: MAT/MOUD Tracking Events

#### `cl_moud_monitoring_overdue`

**Publisher:** CL-21 (MAT/MOUD Tracking)\
**Subscribers:** PF-10 (Notifications)\
**Status:** 📝 Planned\
**Channel:** `cl_events`

**Description:** Fired when a monitoring event (UDS, hepatic panel, etc.) passes its `due_by` timestamp without a `completed_at` value.

**Payload Schema:**

```typescript theme={null}
{
  event: 'cl_moud_monitoring_overdue';
  payload: {
    monitoring_event_id: uuid;
    enrollment_id: uuid;
    chart_id: uuid;
    monitoring_type: 'uds' | 'hepatic_panel' | 'pregnancy_test' | 'other_lab';
    due_by: string;           // ISO timestamp
    days_overdue: number;
  };
  metadata: {
    organization_id: uuid;
    user_id?: uuid;           // System-triggered; may be null
    timestamp: string;        // ISO timestamp
  };
}
```

**PHI Logging Guidelines:**

* **Allowed:** `monitoring_event_id`, `enrollment_id`, `monitoring_type`, `due_by`, `days_overdue`, `organization_id`
* **Prohibited:** `chart_id` should be logged as `has_chart_id: true/false`, not as raw UUID
* **Retention:** Logged to `pf_audit_logs`

**Consumer Actions:**

1. **PF-10 (Notifications):** Alert clinical staff and supervisors of overdue monitoring

***

#### `cl_moud_adherence_risk`

**Publisher:** CL-21 (MAT/MOUD Tracking)\
**Subscribers:** PF-10 (Notifications)\
**Status:** 📝 Planned\
**Channel:** `cl_events`

**Description:** Fired when a patient's medication adherence status indicates risk (e.g., consecutive missed doses or declining adherence pattern).

**Payload Schema:**

```typescript theme={null}
{
  event: 'cl_moud_adherence_risk';
  payload: {
    enrollment_id: uuid;
    chart_id: uuid;
    adherence_status: 'missed' | 'late';
    consecutive_missed_count: number;
    last_event_at: string;    // ISO timestamp of last medication event
  };
  metadata: {
    organization_id: uuid;
    user_id?: uuid;           // System-triggered; may be null
    timestamp: string;        // ISO timestamp
  };
}
```

**PHI Logging Guidelines:**

* **Allowed:** `enrollment_id`, `adherence_status`, `consecutive_missed_count`, `organization_id`
* **Prohibited:** `chart_id` should be logged as `has_chart_id: true/false`, not as raw UUID
* **Retention:** Logged to `pf_audit_logs`

**Consumer Actions:**

1. **PF-10 (Notifications):** Alert prescriber and care team of adherence risk

***

### PF-48: Security Event Detected

**Status:** ✅ Implemented\
**Event:** `security_event_detected`\
**Channel:** Database Webhook on `pf_security_events` INSERT\
**Publisher:** PF-48 (Security Event Monitoring)\
**Subscribers:** PF-04 (Audit), PF-10 (Notifications), PF-36 (Health Dashboard)

**Delivery Mechanism:** Supabase Database Webhook triggers `security-event-alert-delivery` Edge Function on INSERT to `pf_security_events`.

**Payload (webhook record):**

```typescript theme={null}
interface SecurityEventWebhookPayload {
  record: {
    id: string;                    // Event UUID
    organization_id: string;       // Tenant (nullable for pre-auth events)
    event_type: string;            // e.g. 'failed_login', 'permission_violation'
    severity: string;              // 'info' | 'warning' | 'error' | 'critical'
    user_id?: string;              // Affected user (if known)
    ip_address?: string;           // Source IP (INET, nullable)
    is_suspicious: boolean;        // Pattern-based suspicion flag
  };
  type: 'INSERT';
}
```

**Handler Requirements:**

1. Refetch full row from `pf_security_events` by `event_id` before processing
2. Verify `organization_id` matches webhook payload (TOCTOU protection)
3. Match against `pf_security_alert_configs` for active alert rules
4. Deliver via PF-10 with retry (3 attempts, exponential backoff)
5. Write to `pf_security_alert_delivery_failures` (DLQ) on permanent failure

**PHI:** No PHI in payload. Event metadata only (IDs, types, severity).

**Consumer Actions:**

1. **PF-10 (Notifications):** Deliver security alerts to configured recipients
2. **PF-04 (Audit):** Log security event processing
3. **PF-36 (Health Dashboard):** Display security event metrics

***

### PF-43: Quota Violated

**Status:** 📝 Planned\
**Event:** `pf_quota_violated`\
**Publisher:** PF-43 (Quota enforcement framework)\
**Subscribers:** PF-10 (Notifications), PF-48 (Security Event Monitoring — future)

**Purpose:** Notify platform and organization admins when a quota soft or hard limit is exceeded.

**Payload (canonical):** All payload keys use snake\_case. Envelope fields are required for idempotency and routing per Event Schema Standard (§ Idempotency and Retry).

| Field             | Type          | Required | Description                                                                      |
| ----------------- | ------------- | -------- | -------------------------------------------------------------------------------- |
| `event_id`        | string (UUID) | Yes      | Unique idempotency key; consumers MUST skip duplicates                           |
| `occurred_at`     | string        | Yes      | ISO 8601 timestamp when the event occurred                                       |
| `source`          | string        | Yes      | Producer identifier (e.g. `pf-43-quota-enforcement`)                             |
| `spec_version`    | string        | Yes      | Event contract version (e.g. semver `1.0.0`) for evolution                       |
| `event_version`   | string        | Yes      | Contract version for `pf_quota_violated` (semver); required for safe evolution   |
| `organization_id` | string (UUID) | Yes      | Organization the quota applies to                                                |
| `resource_type`   | string        | Yes      | One of: `storage`, `api_calls`, `users`, `custom_objects`, `workflow_executions` |
| `limit_type`      | string        | Yes      | `soft` or `hard`                                                                 |
| `quota_value`     | number        | Yes      | Configured quota value                                                           |
| `actual_usage`    | number        | Yes      | Usage that caused the violation                                                  |
| `violated_at`     | string        | Yes      | ISO 8601 timestamp of the violation                                              |

**Integration Doc:** [PF-43-tenant-resource-quotas-INTEGRATION.md](./tenant-resource-quotas-integration.md) — see `pf_quota_violated` schema and envelope.

**Consumer Actions:**

* **PF-10:** Send notification to platform/org admins per alert threshold and mute settings
* **PF-48:** Ingest security event for monitoring/analytics

***

## PF-36 Phase 2: SLA Violation Events

### `pf.sla.violation.detected`

**Publisher:** PF-36 (System Health Dashboard — SLA Violation Detection)\
**Subscribers:** PF-10 (Notifications)

**Trigger:** `pf-detect-sla-violations` edge function detects metric value breaching SLA threshold.

```typescript theme={null}
{
  event_type: 'pf.sla.violation.detected';
  violation_id: uuid;
  metric_id: uuid;
  metric_name: string;
  threshold_id: uuid;
  severity: 'critical' | 'warning' | 'info';
  current_value: number;
  threshold_value: number;
  organization_id: uuid;
  timestamp: timestamptz;
}
```

**SLA:** Processing \< 1s p95

**Consumer Actions:**

1. **PF-10 (Notifications):** Deliver SLA violation alerts to configured recipients (in-app + email)

***

### `pf.sla.violation.resolved`

**Publisher:** PF-36 (System Health Dashboard — SLA Violation Detection)\
**Subscribers:** PF-10 (Notifications)

**Trigger:** `pf-detect-sla-violations` detects metric returned to within SLA threshold.

```typescript theme={null}
{
  event_type: 'pf.sla.violation.resolved';
  violation_id: uuid;
  metric_id: uuid;
  metric_name: string;
  organization_id: uuid;
  resolved_at: timestamptz;
  duration_minutes: number;
  timestamp: timestamptz;
}
```

**Consumer Actions:**

1. **PF-10 (Notifications):** Deliver resolution notification to original alert recipients

***

## PF-68: Website Chatbot — Lead Captured

### `pf_chatbot_lead_captured`

**Status:** ✅ Implemented\
**Publisher:** `chatbot-lead-capture` edge function\
**Channel:** `domain_events`

**Subscribers:**

| Subscriber             | Action                                        |
| ---------------------- | --------------------------------------------- |
| CE-01 (Contacts/Leads) | Create or update contact and lead records     |
| PF-35 (Webhooks)       | Dispatch webhook to external CRM integrations |

**Payload:**

```typescript theme={null}
interface PfChatbotLeadCapturedPayload {
  organization_id: uuid;
  session_id: uuid;
  contact_id: uuid;
  lead_id: uuid;
  visitor_name: string;
  visitor_email: string;
  source_url: string | null;
  timestamp: timestamptz;
}
```

**Consumer Actions:**

1. **CE-01:** Link lead to chatbot session source, set `source_type = 'chatbot'`
2. **PF-35:** Forward lead data to configured webhook endpoints

***

## CE: Community Engagement Events

### `ce.suppression.created`

**Status:** 📝 Planned (CE-16)
**Publisher:** CE-16 (Communications Compliance & Suppression)
**Channel:** `domain_events`
**Spec Reference:** [CE-16 spec](../../../specs/ce/specs/CE-16-communications-compliance-suppression.md)

**Subscribers:**

| Subscriber              | Action                                                                  |
| ----------------------- | ----------------------------------------------------------------------- |
| CE-08 (SMS)             | Invalidate suppression cache for the contact                            |
| CE-09 (Email Campaigns) | Invalidate suppression cache; remove from in-flight campaign send lists |
| CE-03 (Call Management) | Invalidate DNC/phone cache before next outbound dial                    |

**Payload (IDs only — no PII/PHI):**

```typescript theme={null}
interface CeSuppressionCreatedPayload {
  suppression_id: string;   // uuid
  contact_id: string;       // uuid
  organization_id: string;  // uuid
  channels: Array<'sms' | 'email' | 'phone'>;
  reason: string;           // see ce_suppressions.suppression_reason CHECK
  source: string;           // see ce_suppressions.suppression_source CHECK
  created_at: string;       // ISO 8601
}
```

**Idempotency:** `suppression_id` — subscribers MUST deduplicate.

**PII Handling:** No phone numbers, emails, or names in the payload. Consumers needing contact details MUST resolve via authorized read of `ce_contacts`.

***

### `ce_lead_converted`

**Status:** ✅ Implemented (⚠️ Deprecated — CE-29: use `ce_lead_converted_to_patient` or `ce_lead_converted_to_resident` instead)
**Publisher:** CE-01 (Contacts & Lead Management)\
**Channel:** `domain_events`\
**Spec Reference:** [CE-17 CE–RH Admission Handoff Contract](../../../specs/ce/specs/CE-17-ce-rh-admission-handoff.md)

**Subscribers:**

| Subscriber                  | Action                                        |
| --------------------------- | --------------------------------------------- |
| RH-01 (Resident Management) | Create resident admission from converted lead |

**Payload:**

```typescript theme={null}
interface CeLeadConvertedPayload {
  // Event metadata
  event_id: string; // UUID for idempotency
  organization_id: uuid;
  timestamp: string; // ISO 8601
  
  // Lead/Contact identifiers
  lead_id: uuid;
  contact_id: uuid; // REQUIRED: Consumer must resolve PII via authorized read from ce_contacts
  
  // Conversion metadata
  converted_by: uuid; // User ID who performed conversion
  converted_at: string; // ISO 8601
  conversion_type: 'resident_admission' | 'other';
  conversion_reason?: string;
  
  // Lead-specific data
  lead_data: {
    source_type?: string;
    source_details?: string;
    referral_source_id?: uuid;
    partner_id?: uuid;
    // NOTE: `notes` intentionally excluded — may contain PII/PHI.
    // Consumers needing notes must read from ce_leads via authorized query.
    expected_admission_date?: string;
  };
  
  // RH-specific fields (optional overrides)
  rh_fields?: {
    program_id?: uuid;
    site_id?: uuid;
    admission_date?: string;
    admission_notes?: string;
    referring_partner_id?: uuid;
  };
}
```

**Consumer Actions:**

1. **RH-01:**
   * Resolve contact PII by reading `ce_contacts` via `contact_id` with authorized access (RLS-enforced)
   * Create resident admission record with mapped fields from resolved contact data
   * Check idempotency via `lead_id` + `organization_id` (or fallback to `event_id` from audit table)

**PII Handling:** This event does NOT include PII (names, emails, phones, addresses, DOB) in the payload. Consumers MUST resolve PII by reading from `ce_contacts` using the provided `contact_id` with proper authorization checks. This ensures PII is only accessed by authorized consumers and maintains audit trails.

**Idempotency:** RH consumer MUST check for existing admission using `lead_id` + `organization_id` before creating resident record. If `lead_id` is not available, fallback to `event_id` lookup in audit tables.

***

### `ce_lead_converted_to_patient`

**Status:** 🔜 In Progress\
**Publisher:** CE-29 (Lead-to-Patient Conversion Pipeline)\
**Channel:** `domain_events`\
**Spec Reference:** [CE-29 Integration](./lead-conversion-integration.md)

**Subscribers:**

| Subscriber                            | Action                                    |
| ------------------------------------- | ----------------------------------------- |
| PM-01 (Patient Registration)          | Create patient record from converted lead |
| PM-38 (Intake Appointment Automation) | Auto-schedule intake appointment          |

**Payload:** IDs only (no PII/PHI). See CE-29 integration doc for full schema.

```typescript theme={null}
interface CeLeadConvertedToPatientPayload {
  organization_id: uuid;
  lead_id: uuid;
  contact_id: uuid;
  correlation_id: string;
  converted_by: uuid;
  converted_at: string;
}
```

**Idempotency:** `correlation_id` — subscribers MUST deduplicate.

***

### `ce_lead_converted_to_resident`

**Status:** 🔜 In Progress\
**Publisher:** CE-29 (Lead-to-Patient Conversion Pipeline)\
**Channel:** `domain_events`\
**Spec Reference:** [CE-29 Integration](./lead-conversion-integration.md)

**Subscribers:**

| Subscriber                  | Action                                     |
| --------------------------- | ------------------------------------------ |
| RH-01 (Admission Wizard)    | Create resident record from converted lead |
| PM-39 (Waitlist Management) | Add to waitlist if no bed available        |

**Payload:** IDs only (no PII/PHI). See CE-29 integration doc for full schema.

```typescript theme={null}
interface CeLeadConvertedToResidentPayload {
  organization_id: uuid;
  site_id?: uuid;
  lead_id: uuid;
  contact_id: uuid;
  correlation_id: string;
  converted_by: uuid;
  converted_at: string;
}
```

**Idempotency:** `correlation_id` — subscribers MUST deduplicate.

***

### `donation_received`

**Status:** 📝 Planned\
**Publisher:** CE-18 (Fundraising & Donation Events)\
**Channel:** `domain_events`\
**Spec Reference:** [CE-18 Fundraising & Donation Events](../../../specs/ce/specs/CE-18-fundraising-donation-events-fa.md), [FA-31 CE-FA Donation Revenue Integration](../../../specs/fa/specs/FA-31-ce-fa-donation-revenue-integration.md)

**Subscribers:**

| Subscriber                                 | Action                                     |
| ------------------------------------------ | ------------------------------------------ |
| FA-31 (CE-FA Donation Revenue Integration) | Post donation revenue to GL (FA-02, FA-05) |

**Payload:**

```typescript theme={null}
interface DonationReceivedPayload {
  // Event metadata
  event_id: string; // UUID for idempotency
  organization_id: uuid;
  timestamp: string; // ISO 8601
  
  // Donation identifiers
  donation_id: uuid; // CE donation record ID
  contact_id?: uuid; // Donor contact (if linked)
  
  // Financial data
  amount: number; // Donation amount (positive number)
  currency: string; // ISO 4217 currency code (default: 'USD')
  donation_date: string; // ISO 8601 date
  
  // Fund allocation (REQUIRED for FA-31)
  fund_id?: uuid; // UUID of fa_funds row (optional if fund_type provided)
  fund_type: 'unrestricted' | 'temporarily_restricted' | 'permanently_restricted'; // REQUIRED
  
  // Campaign linkage (optional)
  campaign_id?: uuid; // CE campaign ID
  
  // Payment metadata
  payment_method?: 'cash' | 'check' | 'credit_card' | 'ach' | 'wire' | 'other';
  payment_reference?: string; // Check number, transaction ID, etc.
  
  // Donor information (non-identifying)
  donor_type?: 'individual' | 'organization' | 'anonymous';
  is_anonymous: boolean;
  
  // Additional metadata
  notes?: string;
  custom_fields?: Record<string, unknown>;
}
```

**Consumer Actions:**

1. **FA-31:** Create GL journal entry (debit cash/AR, credit revenue) with fund allocation; check idempotency via `event_id`

**Idempotency:** FA consumer MUST track processed `event_id`s and MUST NOT create duplicate GL entries.

***

### `fundraising_campaign_completed`

**Status:** 📝 Planned\
**Publisher:** CE-18 (Fundraising & Donation Events)\
**Channel:** `domain_events`\
**Spec Reference:** [CE-18 Fundraising & Donation Events](../../../specs/ce/specs/CE-18-fundraising-donation-events-fa.md), [FA-31 CE-FA Donation Revenue Integration](../../../specs/fa/specs/FA-31-ce-fa-donation-revenue-integration.md)

**Subscribers:**

| Subscriber                  | Action                          |
| --------------------------- | ------------------------------- |
| FA-07 (Financial Reporting) | Update campaign revenue reports |
| FA-31 (Optional)            | Generate campaign summary entry |

**Payload:**

```typescript theme={null}
interface FundraisingCampaignCompletedPayload {
  // Event metadata
  event_id: string; // UUID for idempotency
  organization_id: uuid;
  timestamp: string; // ISO 8601
  
  // Campaign identifiers
  campaign_id: uuid; // CE campaign ID
  campaign_name: string;
  
  // Campaign summary
  total_raised: number; // Total donations received
  goal_amount?: number; // Campaign goal (if set)
  completion_date: string; // ISO 8601 date
  
  // Campaign metadata
  campaign_type?: string; // e.g., 'annual_appeal', 'event', 'capital_campaign'
  start_date?: string; // ISO 8601
  
  // Additional metadata
  notes?: string;
  custom_fields?: Record<string, unknown>;
}
```

**Consumer Actions:**

1. **FA-07:** Update campaign revenue reports with completion summary
2. **FA-31 (Optional):** Generate campaign summary journal entry or report flag

**Idempotency:** FA consumer MUST track processed `event_id`s or use `campaign_id` + `organization_id` + `completion_date` composite key.

***

### `ce_web_form_submitted`

**Status:** 📝 Planned\
**Publisher:** CE-10 (Web-to-Lead Capture)\
**Channel:** `domain_events`\
**Spec Reference:** [CE-10 Web-to-Lead Capture](../../../specs/ce/specs/CE-10-web-to-lead-capture.md)

**Subscribers:**

| Subscriber                   | Action                                                                           |
| ---------------------------- | -------------------------------------------------------------------------------- |
| CE-01 (Contacts/Leads)       | Lead already created by CE-10; event provides notification for workflow triggers |
| CE-05 (Pipeline & Reporting) | Update pipeline analytics (web form submission count, conversion tracking)       |
| PF-10 (Notifications)        | Send notification to assigned staff member (if lead assignment configured)       |

**Payload:**

```typescript theme={null}
interface CeWebFormSubmittedPayload {
  // Event metadata
  event_id: string; // UUID for idempotency
  organization_id: uuid;
  timestamp: string; // ISO 8601
  
  // Form identifiers
  form_id: uuid; // CE web form ID
  form_name: string;
  submission_id: uuid; // Web form submission record ID
  
  // Lead/Contact identifiers (created by CE-10)
  contact_id: uuid; // Contact created from submission
  lead_id: uuid; // Lead created from submission (if applicable)
  
  // Submission metadata
  submitted_at: string; // ISO 8601
  source_url?: string; // URL where form was embedded
  utm_source?: string; // UTM parameters for attribution
  utm_medium?: string;
  utm_campaign?: string;
  
  // Submission data (non-identifying summary)
  field_count: number; // Number of fields in submission
  has_phone: boolean; // Whether phone number provided
  has_email: boolean; // Whether email provided
  
  // Additional metadata
  custom_fields?: Record<string, unknown>;
}
```

**Consumer Actions:**

1. **CE-01:** Lead already created; event enables workflow automation triggers
2. **CE-05:** Update pipeline analytics (web form submission metrics)
3. **PF-10:** Send notification to assigned staff member

**Note:** Full submission data is stored in `ce_web_form_submissions` table (accessible via `submission_id`). Event payload contains only summary metadata (no PII).

***

## FW-49: Execution Timeout & Watchdog Events

**Integration:** [FW-49-execution-timeout-watchdog-INTEGRATION.md](./execution-timeout-watchdog-integration.md)\
**See also:** [EVENT\_DELIVERY.md](./EVENT_DELIVERY.md) — when these fire relative to the table-driven automation path.

### `workflow.execution.timed_out`

**Status:** ✅ Implemented\
**Publisher:** FW (via `workflow-timeout-checker` Edge Function; pg\_cron–scheduled)\
**Channel:** `fw_events`\
**Consumers:** FW-47 (DLQ), FW-25 (compensation), FW-22 (monitoring)

```typescript theme={null}
interface WorkflowExecutionTimedOut {
  execution_id: string;
  organization_id: string;
  workflow_definition_id: string;
  on_timeout: 'fail' | 'cancel' | 'escalate';
  deadline_at: string;       // ISO-8601
  timed_out_at: string;      // ISO-8601
  duration_seconds: number;
  error_message?: string;    // Sanitized timeout error description
}
```

### `workflow.execution.deadline_extended`

**Status:** ✅ Implemented\
**Publisher:** FW (via `extend-execution-deadline` Edge Function)\
**Channel:** `fw_events`\
**Consumers:** Audit trail, FW-22 (monitoring)

```typescript theme={null}
interface WorkflowExecutionDeadlineExtended {
  execution_id: string;
  organization_id: string;
  previous_deadline_at: string;  // ISO-8601
  new_deadline_at: string;       // ISO-8601
  extended_by: string;           // user ID
  reason: string;
}
```

***

## FW-47: Dead Letter Queue Alert Events

**Integration:** [FW-47-dead-letter-queue-INTEGRATION.md](./dead-letter-queue-integration.md)\
**Publisher:** FW DLQ threshold monitoring (scheduled job / worker path per integration doc)\
**Channel:** In-app / PF-10 notifications (operational alerts; not necessarily `pg_notify` channels)

### `fw_dlq_threshold_exceeded`

**Status:** ✅ Implemented (operational alert via PF-10)\
**Consumers:** Automation admins, org admins (notification); optional future subscribers for dashboards

**Payload (logical):**

```typescript theme={null}
interface DlqThresholdExceededPayload {
  event_id: string; // UUID — idempotency key for notification delivery / deduplication
  organization_id: string;
  threshold_count: number;
  current_depth: number;
  source_scope?: string; // e.g. org-wide DLQ
  checked_at: string; // ISO-8601
  correlation_id?: string; // optional UUID — links related operational events (aligns with FW-16 / execution correlation)
}
```

> **Note:** `event_id` MUST be a UUID. Timestamps remain ISO-8601, consistent with the document's idempotency/retry guidance.

### `fw_dlq_new_permanent_failure`

**Status:** ✅ Implemented (operational alert via PF-10)\
**Consumers:** Automation admins; links to DLQ entry review UI

**Payload (logical):**

```typescript theme={null}
interface DlqNewPermanentFailurePayload {
  event_id: string; // UUID — idempotency key for notification delivery / deduplication
  organization_id: string;
  dlq_entry_id: string;
  source_type: string;
  source_id: string;
  error_classification?: string;
  failed_at: string; // ISO-8601
  correlation_id?: string; // optional UUID — links related operational events (aligns with FW-16 / execution correlation)
}
```

> **Note:** `event_id` MUST be a UUID. Timestamps remain ISO-8601, consistent with the document's idempotency/retry guidance.

> **Note:** Exact notification payload shapes may mirror PF-10 notification templates; align with `fw_dead_letter_queue` and DLQ settings in FW module.

***

## Planned Events (PF-82 Business Process Registry)

### `process_health_changed`

**Status:** 📝 Planned\
**Publisher:** PF (via `pf_refresh_process_health` scheduled function)\
**Channel:** `domain_events`\
**Consumers:** PF-36 (System Health Dashboard), PF-10 (Notifications)

```typescript theme={null}
interface ProcessHealthChanged {
  processId: string;           // UUID of the process
  organizationId: string;      // Tenant scoping
  processName: string;         // Human-readable process name
  previousStatus: 'healthy' | 'degraded' | 'critical' | 'unknown';
  newStatus: 'healthy' | 'degraded' | 'critical' | 'unknown';
  healthScore: number;         // Composite score 0–100
  topContributingFactor: string; // Component with largest negative impact
  changedAt: string;           // ISO-8601
}
```

### `process_discovered`

**Status:** 📝 Planned\
**Publisher:** PF (via auto-discovery cron)\
**Channel:** `domain_events`\
**Consumers:** PF-04 (Audit Logging)

```typescript theme={null}
interface ProcessDiscovered {
  processId: string;           // UUID of newly created/updated process
  organizationId: string;      // Tenant scoping
  processName: string;         // Discovered process name
  owningCore: string;          // Inferred owning core
  processType: string;         // Inferred process type
  linkedRuleCount: number;     // Number of linked automation rules
  linkedWorkflowCount: number; // Number of linked workflow definitions
  discoveredAt: string;        // ISO-8601
}
```

***

## PF-83: SLA Management Events

### `pf_sla_warning_triggered`

**Status:** 📝 Planned\
**Publisher:** PF (via `pf-sla-checker` edge function)\
**Channel:** `domain_events`\
**Consumers:** PF-10 (Notifications)

```typescript theme={null}
interface PfSlaWarningTriggered {
  slaInstanceId: string;        // UUID
  slaDefinitionId: string;      // UUID
  organizationId: string;       // Tenant scoping
  targetEntityType: string;     // e.g., 'lead', 'admission'
  targetEntityId: string;       // UUID of tracked entity
  warningLevel: number;         // Threshold percentage crossed (e.g., 75, 90)
  percentageElapsed: number;    // Current % elapsed
  deadlineAt: string;           // ISO-8601
  triggeredAt: string;          // ISO-8601
}
```

### `pf_sla_breached`

**Status:** 📝 Planned\
**Publisher:** PF (via `pf-sla-checker` edge function)\
**Channel:** `domain_events`\
**Consumers:** PF-10 (Notifications), FW-03 (Workflow Automation, optional)

```typescript theme={null}
interface PfSlaBreached {
  slaInstanceId: string;        // UUID
  slaDefinitionId: string;      // UUID
  organizationId: string;       // Tenant scoping
  targetEntityType: string;
  targetEntityId: string;
  deadlineAt: string;           // ISO-8601 original deadline
  breachedAt: string;           // ISO-8601
  escalationLevel: number;      // Current escalation level
}
```

### `pf_sla_completed`

**Status:** 📝 Planned\
**Publisher:** PF (via event-driven instance resolution)\
**Channel:** `domain_events`\
**Consumers:** PF-04 (Audit Logging)

```typescript theme={null}
interface PfSlaCompleted {
  slaInstanceId: string;        // UUID
  slaDefinitionId: string;      // UUID
  organizationId: string;       // Tenant scoping
  targetEntityType: string;
  targetEntityId: string;
  startedAt: string;            // ISO-8601
  completedAt: string;          // ISO-8601
  deadlineAt: string;           // ISO-8601
  metSla: boolean;              // Whether completed before deadline
  elapsedSeconds: number;       // Total elapsed time
}
```

***

## PF-91: Compliance Automation & Regulatory Dashboard

**Spec / integration:** [PF-91 spec](../../../specs/pf/specs/PF-91-compliance-automation-regulatory-dashboard.md), [PF-91 integration](./compliance-automation-regulatory-dashboard-integration.md)

### `pf_compliance_drift_detected`

**Status:** 📝 Planned
**Publisher:** PF (via `compliance-run-checks` Edge Function)
**Channel:** `domain_events`
**Consumers:** PF-10 (Notifications), PF-04 (Audit Logging)

```typescript theme={null}
interface PfComplianceDriftDetected {
  organization_id: string;
  compliance_check_id: string; // row id in pf_compliance_checks
  check_type: 'rls_coverage' | 'audit_completeness' | 'phi_access' | 'consent_status' | 'drift_detection';
  severity: 'warning' | 'fail';
  summary: string; // non-PHI description for operators
  dashboard_deep_link: string; // in-app path only; no tokens
  detected_at: string; // ISO-8601
}
```

### `pf_compliance_evidence_ready`

**Status:** 📝 Planned
**Publisher:** PF (via `generate-compliance-evidence` Edge Function)
**Channel:** `domain_events`
**Consumers:** PF-10 (Notifications, optional)

```typescript theme={null}
interface PfComplianceEvidenceReady {
  organization_id: string;
  evidence_id: string;
  framework: 'hipaa' | 'soc2' | 'joint_commission' | 'carf';
  storage_path: string; // opaque path; clients use signed URL flow
  completed_at: string; // ISO-8601
}
```

***

## PF-96: Medicaid State Compliance Configuration

**Spec / integration:** [PF-96 spec](../../../specs/pf/specs/PF-96-medicaid-state-compliance-configuration.md), [PF-96 integration](./medicaid-state-compliance-configuration-integration.md)

### `pf_jurisdiction_profile_changed`

**Status:** 📝 Planned
**Publisher:** PF-96 (on org/site jurisdiction config change)
**Channel:** `domain_events`
**Subscribers:** CL-02, CL-04, CL-11, CL-40, PM-07, PM-08, PM-10, PM-18, PM-41, PF-91
**Version:** 1.0

**Purpose:** Notifies consumers when an organization or site changes its jurisdiction profile assignment, enabling cache invalidation and rule refresh across clinical and billing modules.

**Payload Schema:**

```typescript theme={null}
interface PfJurisdictionProfileChanged {
  event: 'pf_jurisdiction_profile_changed';
  event_version: '1.0';
  payload: {
    event_id: string;              // UUID - unique event identifier for deduplication
    organization_id: string;      // UUID - tenant that changed profile
    site_id?: string;              // UUID - present if site-level change
    old_profile_code: string;      // e.g., "az-ahcccs" or "us-federal-baseline"
    new_profile_code: string;      // e.g., "ca-medi-cal"
    changed_by: string;            // UUID - user who made the change
  };
  metadata: {
    organization_id: string;
    site_id?: string;
    user_id: string;
    timestamp: string;             // ISO-8601
    correlation_id?: string;
  };
}
```

**Deduplication:** Use `event_id` for idempotency.

**Ordering:** Consumers should process events by `timestamp` ascending within each `(organization_id, site_id)` partition.

**Consumer Actions:**

* **CL-02, CL-04, CL-11, CL-40:** Invalidate cached clinical rules; refetch `useClinicalRules()` for assessment/note/consent validation
* **PM-07, PM-08, PM-10, PM-18, PM-41:** Invalidate cached billing rules; refetch `useBillingRules()` for charge capture/claims/scrub
* **PF-91:** Refresh compliance dashboard to reflect new jurisdiction requirements

**Error Handling:** Consumers must handle profile resolution failures gracefully; fallback to federal baseline if new profile unavailable.

***

### `ce_screening_completed`

**Status:** ✅ Implemented\
**Publisher:** CE-28 (Intake Screening & Triage Workflow)\
**Channel:** `domain_events`\
**Spec Reference:** [CE-28 Integration](./intake-screening-integration.md)\
**Implementation:** `src/cores/ce/hooks/useCreateScreening.ts` (client-side, consent-gated per 42 CFR Part 2)

**Subscribers:**

| Subscriber                            | Action                                                              |
| ------------------------------------- | ------------------------------------------------------------------- |
| PM-38 (Intake Appointment Automation) | Auto-create intake appointment when `disposition = 'proceed'`       |
| PM-39 (Waitlist Management)           | Route to waitlist when `disposition = 'waitlist'` or proceed+no-bed |
| CE-29 (Lead Conversion Pipeline)      | Trigger lead-to-patient conversion                                  |
| CL-40 (Clinical Intake Assessment)    | Pre-populate intake assessment from screening data                  |

**Payload:**

```typescript theme={null}
interface CeScreeningCompletedPayload {
  event_id: uuid;
  source: 'ce-28';
  timestamp: string; // ISO 8601
  correlation_id: uuid; // screening attempt ID
  organization_id: uuid;
  data: {
    screening_id: uuid;
    lead_id: uuid;
    disposition: 'proceed' | 'waitlist' | 'refer_out' | 'decline';
    clinical_flag_codes: string[]; // Predefined flag codes only; no free-text PHI
    asam_score: number | null;
    recommended_level_of_care: string | null;
    needs_clinical_escalation: boolean;
    screener_id: uuid;
    screening_date: string; // ISO 8601
    program_type: 'residential' | 'iop' | 'php' | 'outpatient';
    sla_status: 'on_time' | 'missed';
  };
}
```

**Consent Gate (CRITICAL):** This event is only published when `consent_obtained = true` on the screening attempt. No PHI is included in the payload — only IDs and clinical disposition metadata. This complies with 42 CFR Part 2 requirements for SUD data.

**Idempotency:** `correlation_id` (screening attempt ID) — subscribers MUST deduplicate.

***

### `ce_lead_waitlisted`

**Status:** ✅ Implemented\
**Publisher:** CE-28 (conditional — emitted when `disposition = 'proceed'` but bed unavailable)\
**Channel:** `domain_events`\
**Spec Reference:** [CE-28 Integration](./intake-screening-integration.md)\
**Implementation:** `src/cores/ce/hooks/useCreateScreening.ts`

**Subscribers:**

| Subscriber                  | Action                                                    |
| --------------------------- | --------------------------------------------------------- |
| PM-39 (Waitlist Management) | Add lead to waitlist queue with program type and priority |

**Payload:**

```typescript theme={null}
interface CeLeadWaitlistedPayload {
  event_id: uuid;
  source: 'ce-28';
  timestamp: string; // ISO 8601
  correlation_id: uuid; // screening attempt ID
  organization_id: uuid;
  data: {
    lead_id: uuid;
    screening_id: uuid;
    program_type: 'residential' | 'iop' | 'php' | 'outpatient' | 'sober_living' | 'detox' | 'mat' | 'otp';
    reason: 'no_bed_available';
  };
}
```

**Consent Gate:** Only published when `consent_obtained = true`.

**Idempotency:** `correlation_id` — subscribers MUST deduplicate.

***

### `ce_crisis_alert_created`

**Status:** 📝 Planned — CE-28-ENHANCEMENTS EN-01
**Publisher:** CE-28-ENHANCEMENTS EN-01 (Crisis-Keyword AI Alerting)
**Channel:** `domain_events`
**Spec Reference:** [CE-28-ENHANCEMENTS](../../../specs/ce/specs/CE-28-ENHANCEMENTS.md) §EN-01; CONTEXT D-10

**Subscribers:**

| Subscriber                  | Action                                                          |
| --------------------------- | --------------------------------------------------------------- |
| PF-83 (SLA Platform)        | Start crisis SLA timer (Tier-1 = 60s page; Tier-2 = 5min queue) |
| PF-10 (Notifications)       | Page on-call user (Tier-1 only)                                 |
| CE Crisis Queue UI          | Refresh queue / unacknowledged-alert widget                     |
| CE-29 (Conversion Pipeline) | Mark conversion-pipeline aware of crisis hand-off               |

**Payload:**

```typescript theme={null}
interface CeCrisisAlertCreatedPayload {
  event_id: uuid;
  source: 'ce-28-en01';
  timestamp: string; // ISO 8601
  correlation_id: uuid; // ce_crisis_alerts.id
  organization_id: uuid;
  data: {
    alert_id: uuid;
    source_kind: 'sms' | 'web_form' | 'call_transcript' | 'keyword_manual';
    confidence_tier: 'tier_1' | 'tier_2';
    contact_id: uuid;
    screening_attempt_id: uuid | null;
  };
}
```

**PHI Gate (CRITICAL):** Payload contains IDs and tier metadata only — NO patient narrative, NO detected keywords, NO evidence excerpts. Subscribers needing alert detail MUST query the CE API with `alert_id` (RLS-enforced).

**Idempotency:** `correlation_id` (alert ID) — subscribers MUST deduplicate.

***

## CL-14-EN-01: Group Encounter Generation Events

### `cl_group_encounters_approved`

**Contract ID:** `EVT-CL-14-EN-01-001`\
**Publisher:** CL-14-EN-01\
**Subscribers:** PM-07\
**Channel:** `cl_events`\
**Version:** 1.0\
**Purpose:** Notify PM-07 that a reviewed set of generated group encounters has been approved and is ready for charge creation.\
**Trigger:** Batch approval action in CL-14-EN-01 review UI (single or bulk approve).

**Payload Schema:**

```typescript theme={null}
interface ClGroupEncountersApproved {
  event: 'cl_group_encounters_approved';
  event_version: '1.0';
  payload: {
    event_id: string; // UUID
    session_id: string; // UUID
    organization_id: string; // UUID
    approved_generations: Array<{
      generation_id: string; // UUID
      encounter_id: string; // UUID
      patient_id: string; // UUID
      proposed_cpt_code: string;
      duration_minutes: number;
      modifiers: string[];
    }>;
  };
  metadata: {
    organization_id: string; // UUID
    user_id: string; // UUID
    timestamp: string; // ISO-8601
    correlation_id?: string; // UUID
  };
}
```

**PHI:** Payload contains identifiers only; no direct PHI content.
**Idempotency:** `event_id` — PM-07 consumer must deduplicate and process at-most-once per `event_id`.

***

<h2 id="cl-40-clinical-intake">
  CL-40: Clinical Intake & SDOH Assessment Events \\
</h2>

### `cl_intake_finalized`

**Publisher:** CL-40 (on intake assessment finalization)
**Subscribers:** PM-07 (charge creation), CL-18 (SDOH referral follow-up)
**Version:** 1.0

**Payload Schema:**

```typescript theme={null}
interface ClIntakeFinalized {
  event: 'cl_intake_finalized';
  event_version: '1.0';
  payload: {
    event_id: string;                // UUID
    intake_assessment_id: string;    // UUID
    patient_id: string;              // UUID
    chart_id: string;                // UUID
    clinician_id: string;            // UUID
    organization_id: string;         // UUID
    appointment_id?: string;         // UUID — if created from appointment
  };
  metadata: {
    organization_id: string;
    user_id: string;
    timestamp: string;               // ISO-8601
    correlation_id?: string;
  };
}
```

**PHI:** Payload contains IDs only — no PHI per 42 CFR Part 2 / HIPAA.
**Idempotency:** `event_id` — subscribers MUST deduplicate.

***

### `cl_sdoh_referral_created`

**Publisher:** CL-40 (on SDOH screening positive → auto-referral)
**Subscribers:** CL-18 (social referral tracking)
**Version:** 1.0

**Payload Schema:**

```typescript theme={null}
interface ClSdohReferralCreated {
  event: 'cl_sdoh_referral_created';
  event_version: '1.0';
  payload: {
    event_id: string;                // UUID
    referral_id: string;             // UUID — cl_social_referrals.id
    screening_id: string;            // UUID — cl_sdoh_screenings.id
    patient_id: string;              // UUID
    organization_id: string;         // UUID
  };
  metadata: {
    organization_id: string;
    user_id: string;
    timestamp: string;               // ISO-8601
    correlation_id?: string;
  };
}
```

**PHI:** Payload contains IDs only — no PHI.
**Idempotency:** `event_id` — subscribers MUST deduplicate.

***

### `cl_peer_encounter_documented`

**Publisher:** CL-40 (on peer encounter creation/signature)
**Subscribers:** PM-07 (CPT charge creation)
**Version:** 1.0

**Payload Schema:**

```typescript theme={null}
interface ClPeerEncounterDocumented {
  event: 'cl_peer_encounter_documented';
  event_version: '1.0';
  payload: {
    event_id: string;                // UUID
    peer_encounter_id: string;       // UUID
    patient_id: string;              // UUID
    peer_supporter_id: string;       // UUID
    encounter_id?: string;           // UUID — pm_encounters.id
    organization_id: string;         // UUID
  };
  metadata: {
    organization_id: string;
    user_id: string;
    timestamp: string;               // ISO-8601
    correlation_id?: string;
  };
}
```

**PHI:** Payload contains IDs only — no PHI.
**Idempotency:** `event_id` — subscribers MUST deduplicate.

***

***

## PF-98: AI Staff Headshot Generator

### `pf_headshot_job_completed`

**Publisher:** PF-98 (Edge Function `pf-headshot-webhook`)
**Subscribers:** PF-10 (user notification), PF-43 (quota decrement)
**Version:** 1.0
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
interface PfHeadshotJobCompleted {
  event: 'pf_headshot_job_completed';
  event_version: '1.0';
  payload: {
    event_id: string;                // UUID
    job_id: string;                  // UUID — pf_headshot_jobs.id
    user_id: string;                 // UUID — staff member
    organization_id: string;         // UUID
    generated_count: number;         // Number of headshots generated
    provider: string;                // 'headshotpro' | 'replicate' | 'modelslab'
    actual_cost_cents: number;       // Cost in cents for quota tracking
  };
  metadata: {
    organization_id: string;
    user_id: string;
    timestamp: string;               // ISO-8601
    correlation_id?: string;
  };
}
```

**PHI:** Payload contains IDs only — no PHI or biometric data.
**Idempotency:** `event_id` — subscribers MUST deduplicate.

***

### `pf_headshot_campaign_completed`

**Publisher:** PF-98 (Edge Function `pf-headshot-webhook` or `pf-headshot-status-poll`)
**Subscribers:** PF-10 (admin notification)
**Version:** 1.0
**Status:** 📝 Planned

**Payload Schema:**

```typescript theme={null}
interface PfHeadshotCampaignCompleted {
  event: 'pf_headshot_campaign_completed';
  event_version: '1.0';
  payload: {
    event_id: string;                // UUID
    campaign_id: string;             // UUID — pf_headshot_campaigns.id
    organization_id: string;         // UUID
    completed_count: number;         // Staff who completed generation
    total_count: number;             // Total staff invited
  };
  metadata: {
    organization_id: string;
    user_id: string;                 // Campaign admin who created it
    timestamp: string;               // ISO-8601
    correlation_id?: string;
  };
}
```

**PHI:** Payload contains IDs and counts only — no PHI or biometric data.
**Idempotency:** `event_id` — subscribers MUST deduplicate.

***

### `cl_referral_status_updated`

**Publisher:** CL-12-EN-67 (Bi-Directional Referral — status history insert trigger)
**Subscribers:** PF-10 (notifications, audit logging)
**Channel:** `cl_events`
**Version:** 1.0
**Status:** 📝 Planned

**Trigger Conditions:**

* INSERT on `cl_referral_status_history` — fires after a new status entry is recorded for a referral.

**Payload Schema:**

```typescript theme={null}
interface ClReferralStatusUpdated {
  event: 'cl_referral_status_updated';
  event_version: '1.0';
  payload: {
    event_id: string;                // UUID — idempotency key
    organization_id: string;         // UUID
    referral_id: string;             // UUID — references pm_referrals.id (bare UUID)
    status: 'sent' | 'accepted' | 'declined' | 'patient_connected' | 'patient_did_not_connect' | 'closed';
    patient_connected: boolean | null;
    created_at: string;              // ISO-8601
  };
  metadata: {
    organization_id: string;
    user_id: string;                 // UUID — auth.uid() of the user who recorded the status
    timestamp: string;               // ISO-8601
    correlation_id?: string;
  };
}
```

**PHI:** Payload contains IDs and status only — no PHI, patient names, or narrative content.
**Idempotency:** `event_id` — subscribers MUST deduplicate.

***

### PF-100: Platform Ambient Transcription Events

**Status:** 📋 Planned
**Spec:** [PF-100](../../../specs/pf/specs/PF-100-platform-ambient-transcription-and-note-generation.md)
**Integration:** [PF-100 Integration](./platform-ambient-transcription-integration.md)
**Channel:** `pf_transcription_events`
**Common metadata:** every payload includes `{ session_id: uuid, organization_id: uuid, timestamp: ISO-8601, correlation_id: uuid }`. PHI-safe: payloads carry IDs only — never transcript text, names, or clinical narrative. All subscribers MUST deduplicate by `event_id`.

#### Published events

| Event                                       | Publisher | Subscribers                                                   | Purpose / Payload (in addition to common metadata)                                                                                                             |
| ------------------------------------------- | --------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pf.transcription.session.created`          | PF-100    | CL-36 (encounter link), PM-08 (charge prep), PF-91 (evidence) | `{ event_id, module_key, recording_purpose, source, subject_of_record_type, subject_of_record_id?, encounter_id?, jurisdiction_profile_id, is_part2_program }` |
| `pf.transcription.session.consent_verified` | PF-100    | CL-11 (audit), PF-91                                          | `{ event_id, consent_record_type, consent_record_id, jurisdiction_profile_id, is_part2_program }`                                                              |
| `pf.transcription.session.consent_revoked`  | PF-100    | All consumers (STOP downstream processing)                    | `{ event_id, revoked_by, revoked_at, reason? }`                                                                                                                |
| `pf.transcription.session.cancelled`        | PF-100    | All consumers                                                 | `{ event_id, reason, cancelled_by }`                                                                                                                           |
| `pf.transcription.draft.ready`              | PF-100    | CL-36, HR/GR/CE/RH UIs, PF-10 (notify reviewer)               | `{ event_id, draft_id, template_id, generation_latency_ms, requires_manual_drafting: boolean }`                                                                |
| `pf.transcription.draft.attested`           | PF-100    | Consumer core (writes domain record), PF-91, PF-04 (audit)    | `{ event_id, draft_id, reviewer_id, attested_at, attested_content_sha256, ai_vs_final_diff_pct, module_attest_payload?: object }`                              |
| `pf.transcription.audio.deleted`            | PF-100    | PF-91, PF-04, subject-of-record portal                        | `{ event_id, deleted_at, retention_policy }`                                                                                                                   |
| `pf.transcription.deletion_requested`       | PF-100    | Operator alert, PF-91                                         | `{ event_id, requested_by, requested_at, scope: 'audio' \| 'transcript' \| 'draft' \| 'all' }`                                                                 |
| `pf.transcription.deletion_completed`       | PF-100    | PF-91, subject portal                                         | `{ event_id, completed_at, scope }`                                                                                                                            |
| `pf.transcription.policy.violation`         | PF-100    | PF-91 (evidence), PF-10 (notify admin)                        | `{ event_id, violation_type, blocked_at, policy_key }`                                                                                                         |

#### Consumed events

| Event                           | Publisher | PF-100 reaction                                                                                                                                                         |
| ------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pf.consent.cl_consent.revoked` | CL-11     | Triggers session-revocation cascade for any active CL session referencing the consent (publishes `pf.transcription.session.consent_revoked` for each affected session). |
| `pf.encounter.created`          | PM        | Optional auto-link of a clinical session in `pre_record` state to the new encounter.                                                                                    |
| `pf.encounter.cancelled`        | PM        | Cancels any in-progress capture for that encounter (publishes `pf.transcription.session.cancelled` with `reason='encounter_cancelled'`).                                |

**PHI / privacy:** No event payload may contain transcript text, draft content, patient/employee/resident names, or any free-text clinical narrative. Numeric metrics (latency, diff %, counts) and IDs only. Subscribers needing content MUST query the appropriate `pf_transcription_*` table directly (subject to RLS).

**Idempotency:** All events carry `event_id` (UUID). Subscribers MUST deduplicate. Per-event triggers are SECURITY DEFINER and emit at-least-once.

***

## Planned Events (PM-64 AI Coding Assistant)

**Spec:** [PM-64 AI Coding Assistant](../../../specs/pm/specs/PM-64-ai-coding-assistant.md) — 📋 Specification

**Pattern:** Event + Platform Integration Layer. PM-64 consumes a CL-04 event to trigger redaction → RAG → LLM → suggestion, then publishes its own events when suggestions are created and when coders accept / edit / reject. **NO PHI in any payload** (constitution §4.3, GR-06-EN-01).

### CL-04: Note Finalized (consumed by PM-64)

**Event:** `cl_note_finalized`
**Publisher:** CL (Clinical) — CL-04
**Subscribers:** PM-64 (AI coding suggestion trigger), PM-07 (charge capture eligibility), PF-10 (notifications)
**Status:** 📋 Planned (PM-64 will be the first formal consumer)
**Channel:** `cl_clinical_events`
**PHI:** Payload carries IDs only — never note text. PM-64 reads the note via `@/platform/clinical` and runs PHI redaction (fail-closed) before any LLM call.

```typescript theme={null}
{
  event_type: 'cl_note_finalized';
  organization_id: uuid;
  payload: {
    encounter_id: uuid;            // pm_encounters.id
    note_id: uuid;                 // cl_clinical_notes.id
    finalized_at: string;          // ISO timestamp
    finalized_by: uuid;            // pf_profiles.id
    note_type: string;             // e.g. 'progress_note', 'assessment'
    sud_flag: boolean;             // true → consumers must respect 42 CFR Part 2
  };
}
```

### PM-64: AI Coding Suggestion Created

**Event:** `pm.ai_coding_suggestion_created`
**Publisher:** PM (PM-64 `pm-ai-coding-suggest` edge function)
**Subscribers:** PM (Coder UI sidecar — `CodingSuggestionSidecar`), GR (compliance audit), PM-50-EN-01 (fairness drift monitor)
**Status:** 📋 Planned (PM-64)
**Channel:** `pm_events`
**PHI:** None. IDs and model metadata only.

```typescript theme={null}
{
  event_type: 'pm.ai_coding_suggestion_created';
  organization_id: uuid;
  payload: {
    suggestion_id: uuid;           // pm_ai_coding_suggestions.id
    encounter_id: uuid;
    note_id: uuid;
    suggested_at: string;          // ISO timestamp
    vendor: string;                // e.g. 'anthropic-bedrock'
    model_version: string;
    confidence_score: number;      // 0..1
    suggestion_counts: {
      icd10: number;
      cpt: number;
      hcpcs: number;
      modifiers: number;
      em_level_present: boolean;
    };
  };
}
```

### PM-64: AI Coding Decision Recorded

**Event:** `pm.ai_coding_decision_recorded`
**Publisher:** PM (PM-64 `pm-ai-coding-record-decision` edge function)
**Subscribers:** PM-07 (charge capture — only on `accepted` / `edited`), PM-50 (denial-risk model retraining feed), GR (compliance audit queue), PM-50-EN-01 (fairness drift monitor)
**Status:** 📋 Planned (PM-64)
**Channel:** `pm_events`
**PHI:** None. Decision metadata + IDs only; `rejection_reason` is structured (enum) — no free-text narrative.

```typescript theme={null}
{
  event_type: 'pm.ai_coding_decision_recorded';
  organization_id: uuid;
  payload: {
    audit_id: uuid;                // pm_ai_coding_suggestion_audits.id
    suggestion_id: uuid;
    encounter_id: uuid;
    coder_id: uuid;                // pf_profiles.id
    decided_at: string;            // ISO timestamp
    decision: 'accepted' | 'edited' | 'rejected' | 'partial';
    rejection_reason_code?: string; // structured enum, no free text
    edit_summary?: {                // counts only; full diff is in audit row
      codes_added: number;
      codes_removed: number;
      codes_modified: number;
    };
  };
}
```

**Naming exception:** PM-64 events use the dotted `pm.ai_coding_*` form to align with the existing PM-51 RPA naming exception and to namespace the AI coding subsystem cleanly. New non-AI PM events should still follow the `pm_{entity}_{action}` underscore convention.

***

## CL-43: Concurrent Review & Utilization Management Events

> **Status:** 📋 Planned (CL-43). Payloads are **PHI-free** — IDs and structured metadata only (no clinical narrative, no patient demographics).
> **Channel:** `cl_clinical_events`
> **Integration doc:** [CL-43-concurrent-review-utilization-management-INTEGRATION.md](concurrent-review-utilization-management-integration.md)

### CL-43: Review Overdue

**Event:** `cl_review_overdue`
**Publisher:** CL (CL-43 — `cl-review-overdue-scan` cron / trigger on `cl_concurrent_reviews`)
**Subscribers:** PF-10 (notifications — UM coordinator + supervisor escalation), CL-08 (CDS alert surface)
**Status:** 📋 Planned (CL-43)
**Channel:** `cl_clinical_events`
**PHI:** None. IDs only — consumers must read the review record via `@/platform/clinical` if narrative context is needed.

```typescript theme={null}
{
  event_type: 'cl_review_overdue';
  organization_id: uuid;
  payload: {
    review_id: uuid;             // cl_concurrent_reviews.id
    authorization_id: uuid;      // pm_prior_authorizations.id (UUID-only cross-core ref)
    chart_id: uuid;              // cl_patient_charts.id
    reviewer_id: uuid | null;    // pf_profiles.id (assigned UM coordinator, may be null)
    review_due_date: string;     // ISO date — original deadline
    overdue_days: number;        // integer days past review_due_date
    review_type: 'concurrent' | 'continued_stay' | 'level_of_care_change';
    level_of_care: 'residential' | 'php' | 'iop' | 'outpatient';
    escalation_tier: 'soft' | 'supervisor' | 'director'; // derived from grace + escalation thresholds
    detected_at: string;         // ISO timestamp
  };
}
```

**Idempotency:** Consumers MUST dedupe on `(review_id, escalation_tier)` — the scan re-emits at most once per tier per review.

### CL-43: Review Determination Recorded

**Event:** `cl_review_determination_recorded`
**Publisher:** CL (CL-43 — `useRecordDetermination` mutation, post-commit trigger on `cl_concurrent_reviews`)
**Subscribers:** PM-11 (revenue cycle analytics — auth utilization + denial impact)
**Status:** 📋 Planned (CL-43)
**Channel:** `cl_clinical_events`
**PHI:** None. Determination metadata + IDs + payer reference only. `denial_reason_code` is a structured payer reason code (no free-text narrative).

```typescript theme={null}
{
  event_type: 'cl_review_determination_recorded';
  organization_id: uuid;
  payload: {
    review_id: uuid;                 // cl_concurrent_reviews.id
    authorization_id: uuid;          // pm_prior_authorizations.id (cross-core UUID ref)
    chart_id: uuid;                  // cl_patient_charts.id
    determination: 'approved' | 'modified' | 'denied' | 'pending';
    approved_days: number | null;    // days approved by payer (null if denied)
    approved_through_date: string | null; // ISO date
    payer_reference: string | null;  // payer-issued tracking number
    denial_reason_code: string | null; // structured enum/code, no free text
    review_type: 'concurrent' | 'continued_stay' | 'level_of_care_change';
    level_of_care: 'residential' | 'php' | 'iop' | 'outpatient';
    recorded_by: uuid;               // pf_profiles.id
    recorded_at: string;             // ISO timestamp
  };
}
```

**Idempotency:** Consumers MUST dedupe on `review_id` — re-emission only occurs if a prior determination is overturned via appeal (CL-43 publishes a new event with updated determination).

***

## PM-55: ONC HTI-1 / USCDI v3 Patient Access API Events

> **Status:** 📋 Planned (PM-55). Payloads are **PHI-free** — IDs only. Full schemas to be finalized when PM-55 Phase 1 implements the publishers.
> **Naming exception:** PM-55 uses the dotted `pm.fhir_*` form to namespace the FHIR/SMART subsystem (consistent with PM-51 RPA and PM-64 AI Coding exceptions).

### `pm.fhir_app_authorized`

**Publisher:** PM (PM-55 `useGrantAppConsent` mutation / `pm-fhir-token` edge function)
**Subscribers:** PF-04 (audit), GR (compliance metrics)
**Channel:** `pm_events`
**PHI:** None — IDs only.

```typescript theme={null}
{
  event_type: 'pm.fhir_app_authorized';
  organization_id: uuid;
  payload: {
    consent_id: uuid;             // pm_patient_access_consents.id
    patient_id: uuid;
    app_registration_id: uuid;
    scopes_granted: string[];     // SMART scope strings, no PHI
    granted_at: string;           // ISO timestamp
    has_part2_scope: boolean;     // signals SUD-related access
  };
}
```

### `pm.fhir_app_revoked`

**Publisher:** PM (PM-55 `useRevokeAppAccess`)
**Subscribers:** PF-04 (audit), GR
**Channel:** `pm_events`
**PHI:** None.

```typescript theme={null}
{
  event_type: 'pm.fhir_app_revoked';
  organization_id: uuid;
  payload: {
    consent_id: uuid;
    patient_id: uuid;
    app_registration_id: uuid;
    revoked_at: string;
    revoked_reason_code?: 'patient_initiated' | 'admin_revoked' | 'part2_consent_lost' | 'app_suspended';
  };
}
```

### `pm.fhir_information_blocking_logged`

**Publisher:** PM (PM-55 `pm-fhir-router`)
**Subscribers:** GR-08 (incident reporting — escalates when disposition = `info_blocking`)
**Channel:** `pm_events`
**PHI:** None — `denial_narrative` is **NOT** included in event payload (stored only on `pm_information_blocking_log` row, retrieved server-side).

```typescript theme={null}
{
  event_type: 'pm.fhir_information_blocking_logged';
  organization_id: uuid;
  payload: {
    log_id: uuid;                 // pm_information_blocking_log.id
    occurred_at: string;
    patient_id?: uuid;
    app_registration_id?: uuid;
    denial_category:
      | 'preventing_harm' | 'privacy' | 'security' | 'infeasibility'
      | 'health_it_performance' | 'content_manner' | 'fees' | 'licensing';
  };
}
```

### `pm.fhir_access_logged`

**Publisher:** PM (PM-55 `pm-fhir-router` — emitted on every FHIR request, success or denial)
**Subscribers:** PF-04 (HIPAA audit stream)
**Channel:** `pm_events`
**PHI:** None — IDs + status only; no request body, no resource contents.
**Volume note:** High-cardinality. Subscribers should batch.

```typescript theme={null}
{
  event_type: 'pm.fhir_access_logged';
  organization_id: uuid;
  payload: {
    access_log_id: uuid;          // pm_fhir_access_log.id
    patient_id?: uuid;
    app_registration_id?: uuid;
    request_method: 'GET' | 'POST' | 'DELETE';
    resource_type?: string;       // FHIR resource type, no PHI
    status_code: number;
    denied_reason_code?: string;
    occurred_at: string;
  };
}
```

> **Consumed events from CL-11:** `cl.part2_consent_granted` and `cl.part2_consent_revoked` are required by PM-55. **TBD by CL-11 owner** — tracked in `PENDING_CONTRACTS.md` until CL-11 publishes them. If CL-11 cannot publish, PM-55 will fall back to polling `cl_consents.updated_at` per a separate decision log entry.

***

## CL-42: Clinical Pathways & Protocol-Driven Care

**Owning core:** CL · **Channel:** `cl_events` · **Spec:** `specs/cl/specs/CL-42-clinical-pathways-protocol-driven-care.md`

CL-42 publishes 3 canonical snake\_case events. Payloads carry IDs only — no PHI/PII. Consumers join to their own data using the IDs.

### `cl_pathway_milestone_completed`

**Publisher:** CL (`useMilestoneMutations.useCompleteMilestone`)
**Consumers:** CL-10 (outcomes trigger), CL-08 (CDS rule re-evaluation), CL-23 (in-basket task closure)

```ts theme={null}
interface CLPathwayMilestoneCompletedPayload {
  organization_id: string;
  patient_pathway_id: string;
  milestone_id: string;
  milestone_template_id: string;       // template milestone uuid (JSONB)
  template_id: string;
  patient_id: string;                  // pm_patients.id
  completed_by: string;                // pf_profiles.id
  actual_completion_date: string;      // ISO timestamptz
  occurred_at: string;
}
```

**Idempotency:** keyed on `(milestone_id)` — milestone status transitions to `completed` exactly once.
**Retry:** at-least-once delivery; consumers must dedupe on `milestone_id`.

### `cl_pathway_variance_created`

**Publisher:** CL (`useDocumentVariance`)
**Consumers:** CL-08 (CDS rule trigger), GR (variance reporting), CL-15 (quality measures)

```ts theme={null}
interface CLPathwayVarianceCreatedPayload {
  organization_id: string;
  variance_id: string;
  patient_pathway_id: string;
  milestone_id: string;
  template_id: string;
  patient_id: string;                  // pm_patients.id
  reason_code: string;                 // from cl_pathway_variance_reasons picklist
  documented_by: string;               // pf_profiles.id
  documented_at: string;               // ISO timestamptz
  occurred_at: string;
}
```

**Idempotency:** keyed on `(variance_id)`.
**PHI:** `rationale` field is NEVER included in the event payload — only the reason\_code reference.

### `cl_pathway_milestone_overdue`

**Publisher:** CL edge function `cl-pathway-overdue-check` (hourly pg\_cron)
**Consumers:** CL-08 (CDS alert generation), CL-23 (in-basket task creation), GR (compliance tracking)

```ts theme={null}
interface CLPathwayMilestoneOverduePayload {
  organization_id: string;
  patient_pathway_id: string;
  milestone_id: string;
  template_id: string;
  patient_id: string;                  // pm_patients.id
  expected_completion_date: string;    // ISO timestamptz
  hours_overdue: number;
  occurred_at: string;
}
```

**Idempotency:** keyed on `(milestone_id)` — published once per milestone status transition `pending|in_progress` → `overdue`. The cron updates status to `overdue` in the same transaction; subsequent runs skip already-overdue milestones.
**Batching:** processed in batches of 100 milestones per invocation.

## CL-56: Centralized Clinical Notification & Critical Result Alerting Events

### `cl_notification_dispatched`

**Publisher:** CL edge function `cl-clinical-notify`
**Consumers:** CL-25 (audit dashboard SLA metrics)

```ts theme={null}
interface CLNotificationDispatchedPayload {
  organization_id: string;
  event_id: string;                    // cl_notification_events.id
  signal_type: string;                 // e.g. 'lab_critical', 'metabolic_overdue'
  signal_source: string;               // originating spec (e.g. 'CL-09')
  severity: 'informational' | 'urgent' | 'critical';
  chart_id: string | null;
  recipient_user_id: string | null;    // pf_profiles.id
  recipient_role_key: string | null;
  escalation_step: number;
  sla_deadline: string;                // ISO timestamptz
  dispatched_at: string;               // ISO timestamptz
  occurred_at: string;
}
```

**PHI:** No PHI. IDs and severity only — patient name, diagnosis, lab values, and narrative are explicitly prohibited (DB CHECK constraint `chk_cl_notification_no_phi` on `cl_notification_events.payload`).
**Idempotency:** keyed on `(event_id)`. Dedup is enforced upstream by `cl-clinical-notify` (key: `signal_type + chart_id + severity [+ source_record_id]` within `dedup_window_seconds`); only the surviving (non-deduped) event publishes this event.

### `cl_notification_sla_breached`

**Publisher:** CL cron edge function `cl-notification-sla-evaluator` (every 60s)
**Consumers:** GR-09 (incident reporting — auto-creates safety incident for unacknowledged criticals), CL-25 (audit dashboard)

```ts theme={null}
interface CLNotificationSlaBreachedPayload {
  organization_id: string;
  event_id: string;                    // original cl_notification_events.id (breached)
  next_event_id: string | null;        // new escalation event id, or null if chain exhausted
  signal_type: string;
  severity: 'informational' | 'urgent' | 'critical';
  chart_id: string | null;
  escalation_step: number;             // step that breached
  next_escalation_step: number | null; // step the alert was escalated to, if any
  sla_deadline: string;                // ISO timestamptz of breached deadline
  breached_at: string;                 // ISO timestamptz (now())
  chain_exhausted: boolean;
  occurred_at: string;
}
```

**PHI:** No PHI — IDs and severity only.
**Idempotency:** keyed on `(event_id)`. The evaluator sets `sla_breached_at` in the same transaction it publishes; subsequent runs skip events with non-null `sla_breached_at`.

***

## CL-68 / PM-74 / GR-27: BHRF Clinical Residential Episode Lifecycle Events

> Full contract: [CL-GR-PM-BHRF-EPISODE-LIFECYCLE.md](./CL-GR-PM-BHRF-EPISODE-LIFECYCLE.md). BHRF = A.A.C. R9-10-701–722 (adult), a licensed **clinical residential level of care** — distinct from RH recovery housing. **CL is downstream:** GR-27/PM-74 consume CL-68 events but do not depend on CL. No cross-core imports or FKs; `residence_ref`/`chart_ref` are id values from payloads. SUD-identifying context gated by CL-11 (42 CFR Part 2) before emission.
>
> **Idempotency & retry standard (applies to all BHRF events below):** every payload carries a unique `event_id` (UUID) which is the canonical cross-system dedupe key. Consumers MUST record processed `event_id`s and treat duplicates as success (idempotent). The per-event domain tuple listed under **Idempotency** is a secondary guard for replay/race safety. Delivery is at-least-once: on transient consumer errors (5xx, timeout) retry with exponential backoff per the canonical **R7** policy (1s, 2s, 4s; max 3 retries; do not retry 4xx except 429); fatal errors (schema/validation, consent-denied) are not retried and are dead-lettered for review.
>
> **Canonical RH event / alias:** `rh_psychiatric_residential_admission` is a **logical alias** for the canonical RH-01.1 `rh_resident_admitted` event filtered to `facility_type = 'psychiatric_residential'` (and likewise `rh_resident_discharged`). No new RH event is introduced — RH-01.1 canonical names remain authoritative; consumers subscribe to the canonical events and filter by `facility_type`.

### `rh_resident_admitted` (BHRF-filtered view: `facility_type='psychiatric_residential'`)

**Channel:** `rh_events`
**Publisher:** RH (RH-01.1 — canonical `rh_resident_admitted`)
**Consumers:** CL-68 (open clinical episode), PM-74 (per-diem + 5-day exemption), GR-27 (licensure/staffing applicability)
**Status:** 📝 Planned

```ts theme={null}
interface RhPsychiatricResidentialAdmissionPayload {
  event_id: string;              // UUID — canonical dedupe key (required)
  event_type: 'rh_resident_admitted'; // canonical RH-01.1 event; BHRF consumers filter facility_type
  organization_id: string;
  timestamp: string;             // ISO timestamptz
  residence_id: string;          // rh_residences.id value (no cross-core FK)
  chart_id: string;
  site_id?: string;
  admitted_at: string;
  facility_type: 'psychiatric_residential';
  urgency?: 'urgent' | 'routine';
  correlation_id?: string;
}
```

**PHI:** IDs only; no clinical narrative.
**Idempotency:** canonical key `event_id`; secondary domain guard `(organization_id, chart_id, residence_id, admitted_at)`.

### `cl_bhrf_loc_determined`

**Channel:** `cl_events` (single canonical channel)
**Cross-core handoff:** PM-74/GR-27 subscribe to `cl_events` for this contract; do not dual-publish to alternate channels.
**Publisher:** CL (CL-68)
**Consumers:** PM-74 (authorization context), GR-27 (compliance counters)
**Status:** 📝 Planned

```ts theme={null}
interface ClBhrfLocDeterminedPayload {
  event_id: string;              // UUID — canonical dedupe key (required)
  event_type: 'cl_bhrf_loc_determined';
  organization_id: string;
  timestamp: string;
  episode_id: string;
  chart_id: string;
  site_id?: string;
  loc_value: string | null;      // coded level (e.g. 'ASAM 3.5'); null (redacted, not omitted) when CL-11 SUD consent absent/revoked
  determined_at: string;
  correlation_id?: string;
}
```

**PHI:** Coded LOC only; SUD-implying LOC gated by CL-11 before emission.
**Idempotency:** canonical key `event_id`; secondary domain guard `(organization_id, episode_id, determined_at)`.

### `cl_bhrf_clinical_assessment_completed`

**Channel:** `cl_events`
**Publisher:** CL (CL-68)
**Consumers:** GR-27 (15-day timeliness compliance), PM-74 (optional)
**Status:** 📝 Planned

```ts theme={null}
interface ClBhrfClinicalAssessmentCompletedPayload {
  event_id: string;              // UUID — canonical dedupe key (required)
  event_type: 'cl_bhrf_clinical_assessment_completed';
  organization_id: string;
  timestamp: string;
  episode_id: string;
  chart_id: string;
  site_id?: string;
  completed_at: string;
  correlation_id?: string;
}
```

**PHI:** IDs/timestamps only.
**Idempotency:** canonical key `event_id`; secondary domain guard `(organization_id, episode_id, completed_at)`.

### `pm_bhrf_continued_stay_review_required`

**Channel:** `cl_pm_events`
**Publisher:** PM (PM-74)
**Consumers:** CL-43 (Concurrent Review / UM) — PM-74 publishes; it does not import CL-43.
**Status:** 📝 Planned

```ts theme={null}
interface PmBhrfContinuedStayReviewRequiredPayload {
  event_id: string;              // UUID — canonical dedupe key (required)
  event_type: 'pm_bhrf_continued_stay_review_required';
  organization_id: string;
  timestamp: string;
  chart_ref: string;
  residence_ref: string;
  authorization_id: string;
  remaining_days: number;
  expires_on?: string;           // ISO date
  correlation_id?: string;
}
```

**PHI:** No clinical/SUD context on the authorization handoff.
**Idempotency:** canonical key `event_id`; secondary domain guard `(organization_id, authorization_id, expires_on)` — use a stable time boundary (`expires_on`, or `timestamp` if `expires_on` is null). Do **not** dedupe on `remaining_days` (mutable across valid successive reviews — would suppress legitimate continued-stay events).

### `gr_bhrf_compliance_finding_raised`

**Channel:** `gr_events`
**Publisher:** GR (GR-27)
**Consumers:** PF notifications/dashboards
**Status:** 📝 Planned

```ts theme={null}
interface GrBhrfComplianceFindingRaisedPayload {
  event_id: string;              // UUID — canonical dedupe key (required)
  event_type: 'gr_bhrf_compliance_finding_raised';
  organization_id: string;
  timestamp: string;
  residence_ref: string;
  finding_type: 'missing_license' | 'staffing_gap' | 'incident_timeframe' | 'retention_gap';
  due_at?: string;
  correlation_id?: string;
}
```

**PHI:** None — facility/regulatory metadata only.
**Idempotency:** canonical key `event_id`; secondary domain guard `(organization_id, residence_ref, finding_type, COALESCE(due_at, timestamp))` — `due_at` is optional, so fall back to the event `timestamp` to avoid falsely deduping distinct findings that both have `due_at = null`.

### `pm_residential_charge_held`

**Channel:** `pm_events`
**Publisher:** PM (PM-74)
**Consumers:** PF dashboards / notifications (operational held-charge worklist)
**Status:** 📝 Planned

```ts theme={null}
interface PmResidentialChargeHeldPayload {
  event_id: string;              // UUID — canonical dedupe key
  event_type: 'pm_residential_charge_held';
  organization_id: string;
  timestamp: string;             // ISO timestamptz
  service_date: string;          // ISO date of the held per-diem day
  residence_ref: string;
  chart_ref: string;
  hold_reason:                   // coded values only — never free text (no PHI/operational narrative)
    | 'bhrf_continued_stay_auth_required'
    | 'authorization_expired'
    | 'authorization_missing'
    | 'payer_response_pending';
  correlation_id?: string;
}
```

**PHI:** None — billing/operational ids and a coded hold reason only; no clinical/SUD context.
**Idempotency:** canonical key `event_id`; secondary domain guard `(organization_id, residence_ref, chart_ref, service_date, hold_reason)` (one hold per per-diem day per reason). At-least-once delivery; retry per the canonical **R7** policy as stated in the BHRF idempotency & retry standard above.

***

## CE-24: Partner Contract Renewal Notification

**Type:** PF-10 notification (not a domain event).
**Notification type key:** `contract_renewal_reminder`
**Owner:** CE-24 (Partner Document & Contract Management)
**Producer:** `ce-contract-renewal-check` edge function (daily cron, 08:00 UTC)
**Consumer:** PF-10 (`pf_notifications`) — delivered to in-app inbox per user notification preferences.

**Payload (PF-10 notification metadata):**

```ts theme={null}
{
  type: 'contract_renewal_reminder';
  title: string;            // e.g. "Contract Renewal Reminder: [Contract Name]"
                            // Auto-renew contracts prefix with "[Auto-Renew] "
  message: string;          // "[Partner Name] — [Contract Name] expires in [N] days ([End Date])."
  data: {
    contract_id: string;    // ce_partner_contracts.id
    partner_id: string;     // ce_partners.id
    window_days: 30 | 60 | 90;
    end_date: string;       // ISO date
    auto_renew: boolean;
  };
}
```

**Recipients:**

* Contract `created_by` user
* All org users holding permission `ce.contracts.manage` (resolved via `ce_users_with_permission(p_org_id, 'ce.contracts.manage')` SECURITY DEFINER helper)

**Idempotency:** Deduplicated per `(contract_id, notification_window)` via `ce_contract_renewal_log` rows with `action = 'notification_sent'`. Each successful send writes a log row before exiting the per-contract handler.

**PHI:** No PHI — partner and contract metadata only.
