Muin is in private beta.Watch the public release announcement —talk to us.
Falaah Falaah AI

Compliance Training

Assign training programs to employees, track completion, send reminders, escalate overdue assignments, and store certificates in the Documents module.

The Training module is where compliance-related training programs are defined, assigned to employees, and tracked to completion. Every assignment has a due date, a reminder cadence, an escalation path, and a certificate record — so when the auditor asks “has every engineer completed the annual security awareness training,” the answer is a one-query report, not a spreadsheet crawl.

The Shape of a Training Program

A Program is a training course: a name, description, required or optional flag, category, duration, retraining cadence, and (optionally) a link to a training document (PDF, video, external LMS URL). Programs are created once and assigned many times.

An Assignment is a specific employee × program instance: who’s doing what, when it’s due, and what status they’re in (assigned, in_progress, completed, overdue).


Creating a Program

On /compliance/training, click New Program. The form asks for:

FieldPurpose
Namee.g. “Annual Security Awareness”
DescriptionWhat the program covers
Categorysecurity, privacy, hr, safety, technical, regulatory, other
Duration (minutes)Approximate time to complete
Training documentLink to the PDF / video / LMS URL
Retraining cadence (days)How often the training repeats (e.g. 365 for annual)
RequiredIf true, every employee in the assignment scope must complete

Programs can be edited or archived after creation. Archived programs retain history but can’t be assigned new; existing assignments complete normally.


Assigning a Program

Bulk Assignment

On a program’s detail page, click Assign. The picker lets you select:

  • All employees — every active employee in the tenant
  • Department(s) — employees in specific departments
  • Role(s) — employees with specific roles
  • Individual employees — hand-pick from a searchable list

Set a common due date (or use the program’s default: now + retraining_cadence_days). On submit, one TrainingAssignment row per selected employee is created, and notifications fire to each employee.

Single Assignment

From an employee’s profile (HR module), the Assign Training modal lets you pick a program and set a per-employee due date. Useful for ad-hoc assignments — onboarding a new hire into the security awareness program with a 30-day deadline, for example.


The Employee Experience

The IS21 Tile

On the /compliance Today tab, the My Pending Compliance Work widget includes any open training assignments for the current user:

  • Program name
  • Due date + countdown
  • Status badge (assigned, in_progress, overdue)
  • Click-through to the program detail where the employee can launch the training

This is IS21 in the Plan 272 ideal-screen map — the always-visible “what compliance wants from me this week” tile.

Completing an Assignment

From the assignment detail, the employee:

  1. Reviews the training content (inline PDF, video embed, or LMS redirect link)
  2. Clicks Mark Complete after finishing
  3. Optionally uploads a certificate (if the training is from an external LMS that issues one)
  4. The assignment transitions to completed, the completion timestamp is stored, and the next retraining cycle is scheduled (now + retraining_cadence_days)

Native Quiz — Beta Scope

The beta release ships attestation-only completion — the employee clicks “I have completed this training” and the assignment closes. There is no native in-app quiz with scoring, passing thresholds, or retry logic for beta (this is the JG-11 decision per Plan 272a’s component inventory).

Rationale: attestation with audit logging (who clicked complete, when, IP, user agent) satisfies most auditors for routine training, and a full quiz engine is a non-trivial piece of UX that’s tracked post-beta. Tenants with higher-bar training needs can link out to an external LMS (Coursera for Business, Docebo, etc.) that runs the quiz and issues a certificate, then upload the certificate back into Muin on completion.

SCORM — Post-Beta

SCORM package support (native ingestion of .zip SCORM bundles with inline player) is not available at beta. This is tracked for a post-beta release. For beta, SCORM-format training content must be hosted on an external LMS and linked via URL.


The Reminder Worker (R12-REMINDERS)

A daily worker at 07:00 UTC (cron: 0 7 * * *) scans every tenant’s open training assignments.

The Reminder Rules

TriggerActionPriority
Upcoming due (within 7 days, not yet completed)Send TRAINING_DUE_SOON notificationNormal
Overdue (past due date, status assigned or in_progress)Send TRAINING_OVERDUE notificationHigh
Severely overdue (14+ days past due, not already escalated)Send TRAINING_ESCALATED to adminCritical

Cadence and Limits

  • Max 3 reminders per assignment — past that point, the worker stops nagging the employee and escalation takes over
  • Min 3 days between reminders — so the worker doesn’t blast the same person every morning
  • Escalation fires once — the escalated=true flag prevents re-escalation; admin chooses what to do next
  • Per-tenant advisory lockpg_try_advisory_lock(hash('compliance_training:{tenant}')) prevents two worker instances from racing on the same tenant’s pending list

Constants live at the top of muin.server/src/worker/tasks/compliance_training_reminders.py:

MAX_REMINDERS = 3
REMINDER_INTERVAL_DAYS = 3
ESCALATION_THRESHOLD_DAYS = 14
UPCOMING_DUE_DAYS = 7

Idempotency and Reliability

  • last_reminder_at + reminder_sent_count persist per assignment — the worker won’t double-send within the 3-day interval, even across retries
  • Commit-per-assignment — each successful dispatch is persisted immediately after send, so a mid-loop crash can’t lose work or cause duplicate dispatches
  • Per-entity error isolation — an exception on one assignment rolls back its own transaction and counts in failed; remaining assignments continue
  • Eager loadingselectinload(employee.person, training_program) prevents lazy='raise' errors inside the dispatch helpers

The Lazy-Raise Fix (Plan 272e)

Before Plan 272e, the worker occasionally crashed at runtime because of SQLAlchemy lazy='raise' misconfiguration on the employee.person relationship — the reminder helper tried to read attributes that weren’t eagerly loaded. Plan 272e added the selectinload(employee.person, training_program) to the main query so the helper always sees a fully-hydrated employee. The worker now runs clean across the full employee × program assignment list.


Certificate Storage

When an employee uploads a certificate on completion, it flows through the Documents module:

  • document_type is tagged as training_certificate
  • linked_assignment_id points back to the TrainingAssignment row
  • Standard virus scan + versioning + retention lifecycle apply
  • The document is attached to the employee’s profile AND to the assignment itself

On the assignment detail page, the certificate is clickable — opens in the Documents module view with full version history and download.

For audits: Evidence freshness for the Training factor of the compliance score reads the certificate upload timestamps, so keeping certificates current directly improves the score.


Tracking and Reporting

Summary Tiles

The /compliance/training page header shows aggregate tiles:

TileWhat it counts
Active programsPrograms with status=active
Open assignmentsAssignments with status assigned or in_progress
OverdueAssignments past their due date, not yet completed
Completion rateCompleted ÷ total in the current reporting window

Clicking a tile filters the list accordingly.

Assignment List

The Assignments tab shows every assignment with employee name, program name, assigned date, due date, status, and (if complete) completion date + certificate link. Filter by status, program, employee, or due window.

Cross-Framework Evidence

Training completion contributes 15% weight to the compliance score (the Training Compliance factor). Training programs can also be linked to specific framework controls — for example, annual security awareness training maps to SOC 2 CC1.4 (“The entity demonstrates a commitment to attract, develop, and retain competent individuals”). Completion of linked trainings becomes evidence for those controls automatically.


FAQs

How often do reminders fire?

Daily at 07:00 UTC. For each open assignment, the worker fires a reminder if the assignment is within 7 days of due, or past due. Max 3 reminders per assignment, min 3 days between sends. After 14 days overdue, the worker escalates once to the admin and stops nagging the employee. Constants: UPCOMING_DUE_DAYS=7, MAX_REMINDERS=3, REMINDER_INTERVAL_DAYS=3, ESCALATION_THRESHOLD_DAYS=14.

What happens when training expires?

If the program has a retraining_cadence_days set, a new assignment is created automatically cadence_days after the previous completion. So an annual program (cadence=365) re-assigns 365 days after the last completion with a fresh due date (default 30 days out). The employee gets a fresh reminder cycle for the new assignment.

Can I add SCORM modules?

Not at beta — SCORM native support (ingesting .zip SCORM packages with inline playback and completion tracking) is planned post-beta. For beta, host SCORM content on an external LMS (Coursera for Business, Docebo, TalentLMS, etc.) and link via URL. On completion, the employee attests in Muin and uploads the certificate from the external LMS. This flow is audit-valid — the external LMS’s completion event + the Muin attestation + the uploaded certificate together satisfy typical audit evidence requirements.

What if an employee doesn’t complete the training?

Three reminders fire (7 days before due, at due, and 3 days after). At 14 days overdue, the admin gets an escalation notification and a HumanTask. The compliance score’s Training factor drops (completion ratio counts only completed assignments that are in-window). The assignment stays in overdue status until completed or explicitly cancelled by an admin with a cancellation reason.

Is quiz scoring available?

Not natively at beta — completion is attestation-only. The employee clicks “I have completed this training” and the assignment closes with the audit log (user, timestamp, IP, user agent). For training that genuinely needs scored quizzes, link to an external LMS that runs the quiz and issues a certificate; upload the certificate on completion. Native quiz engine is tracked post-beta.