> ## Documentation Index
> Fetch the complete documentation index at: https://docs.alforse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Training

> Training programs, written content, quiz questions, group assignments, per-period completion tracking, and the weekly reminder digest.

**Training** manages required courses, employee-group assignments, and completion records. A training program contains written content and a quiz. Alforse tracks completion for each employee and period, sends weekly reminders for outstanding assignments, and allows managers to record manual completion. Training belongs to the resources area (**Resources → People → Training** and **Assignments**) and uses the `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.

Alforse screenshot**Training detail page: the Questions list on the left, the written content editor in the middle, and the Properties panel on the right**

Questions on the left, the content in the middle, properties on the right.

FieldType

<details>
  <summary>**name**required</summary>

  The training's title.
</details>

<details>
  <summary>**type**`Mandatory | Optional`</summary>

  Whether completion is required. Drives the badge on the list and, for mandatory trainings, the sense of "you must finish this."
</details>

<details>
  <summary>**frequency**`Once | Quarterly | Annual`</summary>

  How often the training must be re-taken. **"Once"** means complete it a single time, forever. **"Quarterly"** and **"Annual"** are *recurring* — completion is tracked per period and resets when a new period begins.
</details>

<details>
  <summary>**status**`Draft | Active | Archived`</summary>

  Lifecycle of the training itself, changed from the page header. See below.
</details>

<details>
  <summary>**content**</summary>

  The written training material, stored as rich JSON (`content`). Employees read it before the questions.
</details>

<details>
  <summary>**grantsAbilityId**</summary>

  The ability completing this training grants or renews.
</details>

<details>
  <summary>**estimatedDuration**</summary>

  A free-text estimate of how long the training takes.
</details>

<details>
  <summary>**tags**</summary>

  Free-form tags for filtering the catalog.
</details>

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.

<details>
  <summary>**Draft**</summary>

  Being authored. Not yet meant for assignment.
</details>

<details open>
  <summary>**Active**</summary>

  Published and in use. Assignments and reminders operate against active trainings.
</details>

<details>
  <summary>**Archived**</summary>

  Retired. Kept for history, no longer assigned.
</details>

NOTE

**Only a Draft training can change**

The content and the questions are editable only while the training is **"Draft"**. Employees can open and complete only an **"Active"** training. To change a published training, set its status back to Draft first.

## 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`):

FieldType

<details>
  <summary>**MultipleChoice**</summary>

  Pick exactly one correct answer from a list of options.
</details>

<details>
  <summary>**MultipleAnswers**</summary>

  Pick one or more correct answers from a list.
</details>

<details>
  <summary>**TrueFalse**</summary>

  A boolean question with a `correctBoolean` answer.
</details>

<details>
  <summary>**MatchingPairs**</summary>

  Match left items to right items, stored as JSON pairs.
</details>

<details>
  <summary>**Numerical**</summary>

  Enter a number; graded against a `correctNumber` within a `tolerance`.
</details>

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.

NOTE

**Assignments target groups, then expand to people**

The assignment stores groups, not employee ids. Alforse expands the groups to their members when it computes who owes the training, so adding a person to a group automatically enrolls them — you don't re-assign.

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](/docs/reference/notifications.md)).

## 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 a `period` 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:

FieldType

<details>
  <summary>**Once**</summary>

  No period (`NULL`). Complete it once and you're done for good.
</details>

<details>
  <summary>**Quarterly**</summary>

  A string like `Q1-2026`. Completion in one quarter doesn't carry into the next.
</details>

<details>
  <summary>**Annual**</summary>

  A string like `2026`. Resets at the start of each year.
</details>

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`):

<details>
  <summary>**Pending**</summary>

  Assigned, in the current period, not yet completed. The default state.
</details>

<details open>
  <summary>**Completed**</summary>

  A completion row exists for this employee and period.
</details>

<details>
  <summary>**Overdue**</summary>

  A recurring period has already ended and the employee never completed it.
</details>

<details>
  <summary>**Not Required**</summary>

  The employee started after the period ended, so they were never on the hook for it.
</details>

HEADS UP

**New hires aren't retroactively overdue**

Recurring trainings check the employee's start date against the period. Someone who joined after a past period closed shows **"Not Required"** for that period, not **"Overdue"** — so onboarding a new hire doesn't instantly paint their record red.

A manager marks completion from the assignment's roster with **"Mark Complete"**; the completion is recorded for the current period (`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, the `weekly` 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.

NOTE

**Reminders stop after five sends per period**

A recurring reminder is capped: once an outstanding training has had five successful reminder emails delivered for the current period, Alforse stops re-sending it. For quarterly and annual trainings the count is keyed to the period, so the cap resets when a new period begins. If a reminder "stopped coming," this cap is usually why.

Two one-time events announce assignments: **"Training assigned to you"** (`training-assignment`) and **"New training available"** (`resource-training-assignment`). See [notifications](/docs/reference/notifications.md) for delivery and preferences.

## Training can grant an ability

An **ability** is an employee's qualification for a process. A training can grant one: set **Grants Ability** in Properties, and completing the training adds that ability to the employee. The scheduler and the shop floor use abilities to decide who may run the process.

Training is one way to grant an ability; a manager can also add it by hand on the person's Abilities page.

**People**

Employees, their abilities, and their training records.

[Open](/docs/reference/people.md)

**Notifications**

Training assignment and reminder delivery.

[Open](/docs/reference/notifications.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.