resources permission for viewing, assignments, and marking completion; editing a training’s fields is checked against the people permission.
For example, create a “Precision Measurement” training with type “Mandatory” and frequency “Annual”, then assign it to the “Quality Inspectors” group. Each group member remains “Pending” for the current year until completion and receives a Sunday reminder while outstanding.
The training catalog
Each training is created from the New Training form, which asks for a Name and optionally Grants Ability (apps/erp/app/modules/resources/ui/Training/TrainingForm.tsx). Configure the remaining fields in the Properties panel (apps/erp/app/modules/resources/ui/Training/TrainingProperties.tsx), which saves each change as you make it.
The status enum is a simple linear lifecycle on the training record — not to be confused with an employee’s completion status further down.
Change the status from the Status selector in Properties, or select Publish in the page header while a training is a Draft.
Written content
A training’s content is written in the editor on the training’s detail page and saved as you type. Employees read it before the questions.Quiz questions
A training can carry a quiz. Each question belongs to one training, is ordered, and is marked required or not. Alforse supports five question types (trainingQuestionType in apps/erp/app/modules/resources/resources.models.ts):
Questions are authored on the training detail page and can be reordered. The stored answer key columns differ by type: options and correctAnswers for the choice types, correctBoolean for true/false, matchingPairs for pairs, and correctNumber / tolerance for numerical.
Assigning training to groups
Trainings are assigned to groups, not individual employees. An assignment links one training to a list of groups. Every employee in those groups receives the assignment. Click an assignment in the list to open its roster: each member with their current status, a completion date if they’ve finished, and a “Mark Complete” button (apps/erp/app/routes/x+/resources+/assignments.$trainingId.tsx). Edit Assignment in the row menu changes its groups. Assigning a training also fires a notification to the newly-covered employees (see notifications).
Completion and status
Completion is recorded once per employee per assignment per period, with a completion timestamp and the person who recorded it. For recurring trainings the record also carries aperiod string, so the same employee isn’t recorded twice for the same period.
The period is the heart of the recurring logic. Alforse derives the current period from the training’s frequency:
An employee’s status is computed, not stored — Alforse evaluates it from whether a completion exists for the current period and when the employee started. There are four possible values (trainingAssignmentStatusOptions in apps/erp/app/modules/resources/resources.models.ts):
apps/erp/app/routes/x+/resources+/assignments.complete.tsx). An employee already “Completed” or “Not Required” has no button — there’s nothing to mark.
The weekly reminder
Every Sunday at 21:00 UTC, theweekly scheduled job (cron 0 21 * * 0, apps/backend/src/runner/native-runner-schedules.ts) finds outstanding training. It selects “Pending” and “Overdue” assignments and sends one digest to each employee.
The notification is the TrainingReminder event (training-reminder) under the Training topic. Its email heading is “Training reminder” and the call-to-action button reads “View training” (packages/web/notifications/src/index.ts). It’s the only recurring notification event in Alforse — so it needs a guard against nagging forever.
Two one-time events announce assignments: “Training assigned to you” (training-assignment) and “New training available” (resource-training-assignment). See notifications for delivery and preferences.