Skip to content

Enrolment gating and staff overrides

Active enrolment (and waitlist to active conversion) runs a single evaluation that gathers all blocking issues at once rather than failing on the first check. The API exposes both a preview (dry run, HTTP 200) and enforce paths that return a problem details document when rules still block the action.

The following checks run for create active and waitlist to active:

  1. Age - Activity minimum/maximum age from effective fields; members without a date of birth may fail with enrollments.date_of_birth_required when any bound applies.
  2. Prerequisites - Level prerequisites via completed levels, required skills, or historical enrolments; MemberLevelOverride bypasses prerequisite checks for a level.
  3. Enrolment policies - Required policies for the target activity, scoped via family billing context; if the member is in more than one family, policy evaluation may require an explicit family_id (enrollments.family_context_required).
  4. Capacity - When available capacity is zero, enrollments.capacity_full blocks active placement (unless overridden by staff).

Each issue is returned with severity (for example blocking), human-readable title / detail, optional pointer and meta, plus can_override and required_permission after annotation.

Staff with the correct Django permission can attest that a specific gate may be bypassed for a given request by sending staff_overrides: a map from issue code to a truthy value (for example { "enrollments.capacity_full": true }).

Rules:

  • Overrides apply per issue code. If staff_overrides[code] is not set, the issue remains.
  • The server checks required_permission for that code. If the user lacks it, the issue is replaced with enrollments.insufficient_permission_to_override (meta.original_code records the gate).
  • Warnings are not overridable via this map (can_override stays false).

Permissions used for enrolment gates (codenames on ActivityEnrollment):

Gate areaPermission codename
Age / DOBactivities.override_enrollment_age
Prerequisitesactivities.override_enrollment_prerequisites
Policiesactivities.override_enrollment_policies
Capacityactivities.override_enrollment_capacity

POST .../eligibility-preview evaluates gates and returns:

  • issues: the same annotated issue objects you would see inside a problem errors array (field names align for client reuse).
  • can_proceed: true when there are no blocking issues.

The preview does not mutate enrolments. It does not apply staff_overrides; it only reflects whether the current actor is staff for can_override hints.

Create enrolment / convert waitlist (enforce)

Section titled “Create enrolment / convert waitlist (enforce)”

Creating an active enrolment or converting waitlist to active applies staff_overrides for staff users. If blocking issues remain, the API responds with 422 Unprocessable Entity, Content-Type: application/problem+json, and problem type:

https://docs.keja.co/troubleshooting/status-codes/enrollments.gates_failed

See the dedicated page for that type and full JSON shape: Enrolment gates failed (enrollments.gates_failed).

  • Drive UI and retry logic from each issue’s code, can_override, and required_permission, not from parsing detail strings.
  • For policy gates when a member belongs to multiple families, pass family_id on create/preview payloads when the API expects family-scoped policy context.
  • Re-run preview after changes (DOB, policy acceptance, family selection) before submitting an enrolment.