Skip to main content

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.

Spec: HR-30
Status: 📝 Planned
Last Updated: 2026-03-25
Constitution: §1.2 (core boundaries), §1.3 (integration patterns)

Integration Overview

IntegrationPatternDirectionStatus
HR-03Event consumerHR-30 consumes📝 Planned
HR-07Data / exportHR-30 → HR-07 staging📝 Planned
HR-06, HR-05, HR-11Same-core readHR-30 reads📝 Planned
PF-10NotificationsHR-30 → PF-10📝 Planned
PF-30RBACPermission keys📝 Planned

Consumed Events

hr_employee_terminated

Publisher: HR-03 (HR core)
Subscriber: HR-30
Status: Planned registry entry (see EVENT_CONTRACTS.md)
Trigger: Employment status set to terminated; existing lifecycle pipeline.
Payload (align with HR-03 / platform event envelope per EVENT_CONTRACTS.md): The event follows the platform event envelope pattern with top-level event_name, event_id, timestamp, and a metadata object. The business payload is wrapped inside the envelope.
interface HrEmployeeTerminatedEventEnvelope {
  event_name: 'hr_employee_terminated';
  event_id: string; // UUID for idempotency and deduplication
  timestamp: string; // ISO 8601 UTC timestamp
  metadata: {
    source: string;
    version: string;
    correlation_id?: string;
  };
  payload: HrEmployeeTerminatedPayload;
}

interface HrEmployeeTerminatedPayload {
  employee_id: string;
  organization_id: string;
  termination_date: string; // ISO date
  termination_type: 'voluntary' | 'involuntary' | 'retirement' | 'end_contract';
  offboarding_instance_id?: string | null;
}
Idempotency & Retry Semantics:
  • Deduplication key: event_id (must be unique per event instance)
  • Business idempotency: Unique partial index or application check on (organization_id, employee_id, termination_date) ensures at-most-once creation of final paycheck request
  • Retry behavior: Consumer must handle duplicate event_id gracefully (idempotent INSERT); retries with same event_id are no-ops
  • Ordering: Events for the same employee_id should be processed in timestamp order where possible; out-of-order events are handled via business-key uniqueness check
Consumer action (HR-30):
  1. Verify event_id not already processed (optional deduplication table or log check).
  2. Map termination_type to HR-30 enum per spec Clarifications.
  3. Insert hr_final_paycheck_requests if no row for (organization_id, employee_id, termination_date) with non-cancelled status.
  4. Enqueue calculation job (status → calculating).
Publishers and consumers must follow EVENT_CONTRACTS.md rules for envelope structure, metadata fields, and idempotency guarantees.

Published Events (optional Phase 2)

hr_final_paycheck_status_changed

Publisher: HR-30 Subscribers: PF-10 (notifications), HR-07 (future pay run hooks) Status: 📝 Planned — event type is defined in KnownEventName but not yet seeded in fw_workflow_events. Confirm registration in seed data during implementation. Payload (draft):
interface HrFinalPaycheckStatusChangedPayload {
  event_name: 'hr_final_paycheck_status_changed';
  request_id: string;
  employee_id: string;
  organization_id: string;
  previous_status: string;
  new_status: string;
  deadline_date: string;
  timestamp: string;
}

HR-07 Handoff

Phase 1: CSV export from UI + documented column mapping (employee id, amounts, pay date).
Phase 2: Structured RPC or edge function hr_export_final_pay_for_run returning JSON lines for payroll import — blocked on HR-07 pay-run API shape; tracked in PENDING_CONTRACTS.md.

Platform Integration Layer

  • Use @/platform/events (or existing HR event dispatcher) for emitting/consuming typed events.
  • Notifications: @/platform/notifications patterns; no PHI in notification body (ids and deadline only).

Security

  • All access gated by RLS + hr_has_permission / is_hr_admin / hr_is_manager_of / is_self_employee per spec.
  • Edge functions: verify_jwt: true; getCorsHeaders; structured logger.

References