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:
| Field | Purpose |
|---|---|
| Name | e.g. “Annual Security Awareness” |
| Description | What the program covers |
| Category | security, privacy, hr, safety, technical, regulatory, other |
| Duration (minutes) | Approximate time to complete |
| Training document | Link to the PDF / video / LMS URL |
| Retraining cadence (days) | How often the training repeats (e.g. 365 for annual) |
| Required | If 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
activeemployee 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:
- Reviews the training content (inline PDF, video embed, or LMS redirect link)
- Clicks Mark Complete after finishing
- Optionally uploads a certificate (if the training is from an external LMS that issues one)
- 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
| Trigger | Action | Priority |
|---|---|---|
| Upcoming due (within 7 days, not yet completed) | Send TRAINING_DUE_SOON notification | Normal |
Overdue (past due date, status assigned or in_progress) | Send TRAINING_OVERDUE notification | High |
| Severely overdue (14+ days past due, not already escalated) | Send TRAINING_ESCALATED to admin | Critical |
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=trueflag prevents re-escalation; admin chooses what to do next - Per-tenant advisory lock —
pg_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_countpersist 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 loading —
selectinload(employee.person, training_program)preventslazy='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_typeis tagged astraining_certificatelinked_assignment_idpoints back to theTrainingAssignmentrow- 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:
| Tile | What it counts |
|---|---|
| Active programs | Programs with status=active |
| Open assignments | Assignments with status assigned or in_progress |
| Overdue | Assignments past their due date, not yet completed |
| Completion rate | Completed ÷ 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.
Related
- Compliance Health — training compliance is 15% of the score
- Compliance Frameworks — link programs to framework controls
- Policy hub — related attestation workflow
- Document assembly — where training certificates are stored