The models
Coverage thins toward the top of that list. Where a system does not separate content from courses, content is sparse or absent, and many LMS platforms have no concept of skills at all, so that model comes back empty for those integrations.
How they connect
An enrollment points straight at its completion, so finding outstanding training is a null check on a record you already hold, not a join you build. An enrollment with an emptycompletion is training assigned but not finished, and in a compliance context that gap is the report.
Course and content reference each other both ways, so one video used across three courses is one record rather than three. Skills attach to courses and content the same way.
A learner is not an employee. LMS user IDs and HRIS employee IDs do not correspond, so join on email_address and keep a bucket for learners with no employee record - contractors, leavers and outside participants routinely have one without the other.
How many per user
A completion references either a
course or a content, so finishing one module counts as its own completion. Count completions without checking which field is set and you overstate how many full courses someone finished.
Recurring compliance training produces one dated completion per cycle rather than overwriting the last, which is why the two models stay separate: a single record with a status field could only hold the most recent one.
Related
- Passthrough - the only write route for LMS
- Record identity - matching learners to employees
- Scoping - why a model can come back empty
- Authentication - why an HRIS token returns
403on LMS