Course
Data Entity
Description
Training and certification course offered to peer mentors, with prerequisite requirements, schedule, and seat capacity. Completing a course issues a certification; HLF uses certifications as an eligibility gate that auto-removes expired peer mentors from assignment pools.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key, generated server-side via gen_random_uuid() | PKrequiredunique |
organization_id |
uuid |
Foreign key to organizations. Scopes the course to a specific member organization; only users affiliated with this org can enroll. | required |
title |
string |
Human-readable course name shown in the catalog and detail screens (e.g., 'Likeperson grunnkurs 2025'). Maximum 255 characters. | required |
description |
text |
Full-length course description covering learning outcomes, content overview, and any special requirements. Rendered as markdown in Course Detail Screen. | - |
course_type |
enum |
Delivery modality of the course. Determines which schedule fields are mandatory and affects UI rendering. | required |
prerequisites |
json |
Array of certification type identifiers that a peer mentor must hold before enrolling. Empty array means no prerequisites. Validated by CourseEnrollmentService at enrollment time. Example: ["peer-mentor-basic", "first-aid"]. | required |
schedule |
json |
Structured schedule object containing session details. Shape: { start_date: ISO-date, end_date: ISO-date, location: string | null, sessions: [{ date: ISO-date, start_time: string, end_time: string, location: string | null }] }. Required for in_person and hybrid types. | - |
instructor_name |
string |
Name of the course instructor or facilitator, displayed on the Course Detail Screen. Optional for self-paced courses. | - |
location |
string |
Primary venue or platform for the course (e.g., 'Oslo Kongressenter' or 'Zoom'). Redundant for structured schedule sessions but provides a quick summary for list views. | - |
seats_total |
integer |
Maximum number of concurrent enrollments allowed. Must be a positive integer. A value of -1 may represent unlimited seats for self-paced courses. | required |
seats_available |
integer |
Denormalized count of remaining open seats. Decremented on confirmed enrollment, incremented on withdrawal or cancellation. Enforced by database trigger to prevent negative values. Real-time updates streamed via Supabase Realtime. | required |
enrollment_deadline |
datetime |
UTC timestamp after which new enrollments are rejected. Must be before the course start_date in the schedule. Displayed with countdown on Course Detail Screen. | - |
certification_type |
string |
Identifier for the type of certification issued upon successful completion (e.g., 'peer-mentor-basic', 'hearing-aid-specialist'). Used by CertificateService to set the certification_type field on the resulting certifications record. | required |
certification_validity_months |
integer |
Number of months the issued certification remains valid after completion. Drives expiry_date computation on the certifications record. Critical for HLF: expired certifications auto-remove peer mentors from active pools via the CertificateExpiryScheduler. | required |
duration_hours |
decimal |
Total estimated learning time in hours. Used in catalog display and Bufdir reporting for training hours contributed by peer mentors. | - |
is_active |
boolean |
Soft-delete / visibility flag. Inactive courses are hidden from Course Catalog Screen and block new enrollments. Existing enrollments on deactivated courses are preserved for certification issuance. | required |
is_recurring |
boolean |
Indicates whether this course is offered on a recurring schedule. Recurring courses generate new schedule instances; enrollment_deadline and schedule are reset per instance by admin. | required |
max_enrollments_per_user |
integer |
Maximum number of times a single user may enroll in this course across all time. Typically 1 for certification courses; may be higher for refresher or workshop-style courses. | required |
created_by |
uuid |
User ID of the admin or coordinator who created the course record. Foreign key to users. Used in audit log display. | required |
created_at |
datetime |
UTC timestamp of record creation, set server-side via now(). | required |
updated_at |
datetime |
UTC timestamp of last modification, updated via trigger on any field change. | required |
Database Indexes
idx_courses_organization_id
Columns: organization_id
idx_courses_organization_id_is_active
Columns: organization_id, is_active
idx_courses_enrollment_deadline
Columns: enrollment_deadline
idx_courses_certification_type
Columns: certification_type
idx_courses_organization_id_certification_type
Columns: organization_id, certification_type
idx_courses_is_active_enrollment_deadline
Columns: is_active, enrollment_deadline
Validation Rules
title_not_empty
error
Validation failed
seats_total_positive
error
Validation failed
enrollment_deadline_before_start
error
Validation failed
certification_validity_positive
error
Validation failed
schedule_required_for_synchronous_types
error
Validation failed
prerequisites_valid_certification_types
error
Validation failed
organization_id_exists
error
Validation failed
certification_type_format
error
Validation failed
seats_available_lte_seats_total
error
Validation failed
upcoming_deadline_warning
warning
Validation failed
Business Rules
seat_capacity_enforcement
A new enrollment is rejected if seats_available equals 0 at the moment of the enrollment request. The check and the decrement of seats_available must occur within a single database transaction to prevent race-condition overbooking. This is enforced via a Supabase RPC call rather than a client-side check.
prerequisite_certification_check
Before confirming enrollment, CourseEnrollmentService queries the certifications table for the enrolling user and verifies that each certification_type listed in the course's prerequisites array exists and is not expired. Enrollment is blocked if any prerequisite is missing or expired.
enrollment_deadline_enforcement
Enrollment attempts received after enrollment_deadline are rejected with a deadline-passed error. The deadline is checked server-side in the enrollment RPC to prevent client clock manipulation.
certification_issuance_on_completion
When a course_enrollment record transitions to status 'completed', CertificateService automatically creates a certifications record for the user, setting issue_date to now() and expiry_date to now() + certification_validity_months. The certification_type on the new record is copied from the course.
hlf_expired_cert_auto_removal
For organizations with the HLF certification gate enabled, the CertificateExpiryScheduler runs a daily job: any peer mentor whose required course certification has expired has their peer_mentor_availability status automatically set to 'paused'. The coordinator is notified via push notification. This enforces HLF's policy that expired certifications remove peer mentors from active assignment pools.
organization_scope_isolation
Supabase RLS policies on the courses table restrict SELECT to users whose user_organization_memberships includes the course's organization_id. INSERT, UPDATE, and DELETE are restricted to users with admin or coordinator roles in that organization. Cross-organization course visibility is not permitted.
max_enrollment_per_user_limit
If max_enrollments_per_user is 1 (the default), a user may not enroll in the same course more than once. CourseEnrollmentService queries existing enrollment records before creating a new one and rejects the request with an 'already enrolled' error if the limit is reached.
inactive_course_blocks_enrollment
If is_active is false, the course is hidden from Course Catalog Screen and any direct enrollment attempt is rejected server-side. Existing enrollments and issued certifications are unaffected by deactivation.
seats_available_consistency
A database trigger maintains seats_available as seats_total minus the count of confirmed and completed course_enrollments. The trigger fires on INSERT, UPDATE, and DELETE of course_enrollments to keep the denormalized count consistent. seats_available may never be negative or exceed seats_total.
physical_card_parallel_system
For HLF, digital certification issuance does not replace the physical peer mentor card. The certifications record carries a physical_card_issued boolean flag that coordinators must manually confirm separately. The Course and Certificate screens surface both statuses simultaneously to coordinate parallel workflows.
CRUD Operations
Storage Configuration
Entity Relationships
Each certification is issued upon successful completion of a specific course
A course may have multiple enrolled users up to its configured seat capacity
Courses are offered by specific organizations and scoped for enrollment eligibility and certificate issuance