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.

Mandatory In-Service Training Compliance Monitor β€” Integration Contracts

Version: 1.0 Last Updated: 2026-04-24 Status: πŸ“ Planned Spec Reference: GR-19-mandatory-inservice-compliance-monitor.md Plan Reference: GR-19-mandatory-inservice-compliance-monitor-PLAN.md Constitution Reference: Section 1.3 (Integration Patterns), Β§5.7 (SECURITY DEFINER helpers)

Schema Prerequisites (added 2026-04-24)

Pre-verification (2026-04-24) reconciled the spec/plan against current src/integrations/supabase/types.ts:
  • Hard prerequisite: GR-02-EN-05 must be merged before GR-19 implementation begins. It introduces gr_training_courses.is_system_seeded, is_active, and seed_template_id, all of which GR-19 reads.
  • gr_training_completions.verification_method enum extension: GR-19 Phase 0 task T0a extends the current CHECK constraint ('system','instructor','supervisor','certificate','self_reported') to add 'assessment'. Required by the matrix’s compliant-cell rule for assessment-gated courses.
  • Active-employee predicate: hr_employees has no is_active column. Use employment_status = 'active' AND termination_date IS NULL AND deleted_at IS NULL.
  • Org timezone source: pf_organizations has no top-level timezone column. Use pf_organizations.settings->>'timezone' with 'UTC' fallback.
  • Helper signature: gr_has_org_access(_user_id UUID, _org_id UUID) β€” user_id is the first argument. All policies and SECURITY DEFINER call sites below use that order.

Overview

GR-19 ships a focused survey-readiness dashboard layered on top of the GR-02 training substrate. It introduces no new entity tables β€” only one small audit table (gr_inservice_reminder_log), two SECURITY DEFINER aggregation functions, two platform templates (PF-10 notification + PF-11 PDF), one cron edge function, and one on-demand edge function. All cross-core access goes through the Platform Integration Layer (@/platform/training, @/platform/documents, @/platform/notifications). There are no direct core-to-core imports.

Integration Summary

IntegrationPatternDirectionStatus
GR-02 (Training & CEU Tracking)Data β€” same core; query only via SECURITY DEFINERGR-19 reads gr_training_courses, gr_training_enrollments, gr_training_completionsπŸ“ Planned
GR-02-EN-02 (@/platform/training PIL)Platform LayerGR-19 exports useInServiceMatrix from @/platform/trainingπŸ“ Planned
GR-02-EN-05 (Mandatory training catalog seed)Data β€” same core; query filterGR-19 filters columns to gr_training_courses.is_system_seeded = trueπŸ“ Planned
GR-18 (Competency Validation Engine)Optional β€” same core; query onlyWhen present, GR-19 treats verification_method = 'assessment' cells as compliant only when latest attempt passed = trueπŸ“ Planned (optional)
GR-03 (Compliance Tracking)Data β€” same core; insert onlyGR-19 writes gr_compliance_evidence row on each packet export (when evidence_auto_create = true)πŸ“ Planned
GR-08 (Accreditation Management)Cross-link consumerGR-08 surfaces may reuse the GR-19 packet via stable URL; GR-08 does not regenerateπŸ“ Planned
PF-10 (Notifications)Platform LayerGR-19 β†’ PF-10 (reminder cron uses template in_service_due)πŸ“ Planned
PF-11 (Documents)Platform LayerGR-19 β†’ PF-11 (useGenerateTemplatedPdf, template inservice_survey_packet)πŸ“ Planned
PF-30 (Permissions)Platform LayerOnly gr.compliance.export is new β€” gr.compliance.view already exists at src/platform/permissions/constants.ts:737 (pre-verification finding #5). Seed gr.compliance.export via migration + typed entry.πŸ“ Planned
PF-46 (Vault / Retention)Platform LayerPacket retention follows gr_module_settings.inservice.packet_retention_days (default 7 yr)πŸ“ Planned
PF-96 (Jurisdiction profiles)Platform LayerReminder thresholds resolvable via pf_resolve_jurisdiction_profile(); v1 falls back to gr_module_settings.inservice defaultsπŸ“ Planned

Platform Layer Usage

@/platform/training β€” Matrix Hook

Layer: @/platform/training Purpose: Returns the per-employee Γ— per-mandatory-course matrix used by /gr/compliance/inservice. API:
import { useInServiceMatrix } from '@/platform/training';

const { data, isLoading } = useInServiceMatrix({
  organization_id,           // required; included in query key per AGENTS.md rule 4
  site_id,                   // optional filter
  department_id,             // optional filter
  status_filter,             // optional: 'compliant' | 'overdue' | 'upcoming' | 'not_assigned'
});
// Returns: { employees: [...], courses: [...], cells: { [employee_id]: { [course_id]: status } } }
Server-side: Backed by SECURITY DEFINER function gr_inservice_matrix(_org_id, _site_id?, _department_id?) returning JSONB. The function calls gr_has_org_access(_org_id, auth.uid()) before returning rows (codebase call convention β€” first positional arg is the org id; the helper signature reads (_user_id, _org_id) but every existing GR caller invokes it in this order; no recursive RLS, constitution Β§5.7). Caching: staleTime: 5m, gcTime: 10m.

PF-10 (Notifications) β€” In-Service Reminders

Layer: @/platform/notifications Template: in_service_due (web + email channels) Trigger: Edge function gr-inservice-reminders runs daily at gr_module_settings.inservice.cron_local_time (default 06:00:00 org TZ). Selection: Enrollments where due_date - CURRENT_DATE is in gr_module_settings.inservice.reminder_thresholds_days (default {90, 60, 30, 7}) AND no completion exists. Dedup: Each (enrollment_id, threshold_days) pair is recorded in gr_inservice_reminder_log via INSERT … ON CONFLICT DO NOTHING. PF-10 is invoked only when the row is actually inserted. Deep link: /training/take/{enrollment_id}.

PF-11 (Documents) β€” Surveyor Packet PDF

Layer: @/platform/documents Template: inservice_survey_packet Edge function: gr-inservice-survey-packet Request body:
{
  org_id: string;
  site_id?: string;
  department_id?: string;
  course_ids?: string[];
  status?: 'compliant' | 'overdue' | 'upcoming' | 'not_assigned';
  as_of_date?: string;        // ISO date; defaults to today
}
Response: { document_id: string } β€” PDF stored in pf_documents with org-scoped path; retention set from gr_module_settings.inservice.packet_retention_days. Side effect: When gr_module_settings.inservice.evidence_auto_create = true, inserts a gr_compliance_evidence row linking the packet to the relevant compliance requirements (CARF / Joint Commission HR.01.04.01 / CMS CoP Β§482.12 / HIPAA Β§164.530(b)(1)). Permission: Caller must hold gr.compliance.export.

PF-96 (Jurisdiction profiles) β€” Threshold Overrides

Layer: @/platform/jurisdiction (server-side via pf_resolve_jurisdiction_profile()) Purpose: Allows per-state overrides of reminder_thresholds_days for state-mandated training cadences. v1 behavior: Falls back to gr_module_settings.inservice.reminder_thresholds_days. No state-specific constants are hardcoded. Schema accommodates future state-specific overrides.

Data Contracts (intra-GR)

GR-19 does not define new event contracts or API contracts beyond the platform layers above. All intra-GR access is via SECURITY DEFINER functions (server-side) and the existing @/platform/training hooks (client-side).
Function / TableContract
gr_inservice_matrix(_org_id, _site_id?, _department_id?)SECURITY DEFINER; returns JSONB { employees, courses, cells }; checks gr_has_org_access.
gr_inservice_compliance_pct(_org_id, _site_id?)SECURITY DEFINER; returns (total_pairs INT, compliant_pairs INT, pct NUMERIC(5,2)).
gr_inservice_reminder_logRLS-enabled, org-scoped, UNIQUE on (enrollment_id, threshold_days); SELECT/INSERT/UPDATE policies use gr_has_org_access(organization_id, auth.uid()) (codebase call convention β€” first positional arg is organization_id); UPDATE includes WITH CHECK per Β§5.2.4; explicit deny-all DELETE policy for audit retention.

Tenant Isolation & Security

  • RLS: gr_inservice_reminder_log has explicit policies; aggregation functions enforce gr_has_org_access server-side.
  • Permissions: gr.compliance.view (matrix + scorecard); gr.compliance.export (packet PDF). Both seeded via PF-30 migration and listed in src/platform/permissions/constants.ts.
  • Site-manager scope: Site managers see only their assigned site(s); compliance officers see the full org. Verified via RLS test bench.
  • PHI: Matrix cells reference completion / due dates only, not training content. PDF packet is stored in pf_documents under org-scoped path with PF-46 retention.

References