Learn Reference Public

Module Research Notes

Evidence gathered from the current Learn module files — controllers, models, configs, and migrations — before writing these user guide pages.

Guide version: r1 Module version: 1.0.0 Updated: 2026-07-22 Estimated time: 4 min 2 views
Reference

Module Research Notes

Evidence gathered from the current module files before writing the user guide pages.

Slug: coursesVersion: 1.0.0Category: LearningsReviewed: 2026-07-11

Research Sources Inspected

Source path

modules/Learn

Feature flags marked true

  • Controllers
  • Models
  • Views
  • Language
  • Permissions
  • Left Menu
  • Routes
  • Migrations
  • Cron Jobs
  • Api Endpoints

Evidence Summary

Manifest

module.json defines slug courses, version 1.0.0, category Learnings, and the module capability flags used in this guide.

Runtime surface

29 controller file(s), 73 view file(s), and 77 route mapping(s) were found.

Data surface

23 model file(s), 17 declared table(s), and 20 migration file(s) were found.

Operations surface

9 permission key(s), 1 job(s), 2 seeder(s), and 0 test file(s) were found.

Detailed File Evidence

Controllers and methods

  • Certifications
  • Course_categories
  • Course_choices
  • Course_discussions
  • Course_enrollments
  • Course_enumerations
  • Course_essays
  • Course_exams
  • Course_groups
  • Course_modules
  • Course_portal
  • Course_questions
  • Courses
  • Instructor_applications
  • Learn_ai
  • Learn_api_courses - index, view
  • Learn_attempts
  • Learn_certificate_templates
  • Learn_certificates
  • Learn_gradebook
  • Learn_me_courses - index, view
  • Learn_points
  • Learn_settings - seo, save_seo_settings
  • Learn_student
  • Skillsets
  • Skillsets_job_function
  • Skillsets_workforce
  • University
  • University_settings

Jobs and schedules

  • Sync public catalog counts (30 3 * * *) - Recomputes each tenant\

Routes sampled

RouteTarget
learn/coursesCourses/index
learn/courses/(:any)Courses/$1
learn/courses/(:any)/(:any)Courses/$1/$2
learn/course_categoriesCourse_categories/index
learn/course_categories/(:any)Course_categories/$1
learn/course_categories/(:any)/(:any)Course_categories/$1/$2
learn/course_enrollmentsCourse_enrollments/index
learn/course_enrollments/(:any)Course_enrollments/$1
learn/course_enrollments/(:any)/(:any)Course_enrollments/$1/$2
learn/course_modulesCourse_modules/index
learn/course_modules/(:any)Course_modules/$1
learn/course_modules/(:any)/(:any)Course_modules/$1/$2
learn/course_groupsCourse_groups/index
learn/course_groups/(:any)Course_groups/$1
learn/course_groups/(:any)/(:any)Course_groups/$1/$2
learn/course_groups/(:any)/(:any)/(:any)Course_groups/$1/$2/$3
learn/course_examsCourse_exams/index
learn/course_exams/(:any)Course_exams/$1
learn/course_exams/(:any)/(:any)Course_exams/$1/$2
learn/course_exams/(:any)/(:any)/(:any)Course_exams/$1/$2/$3
57 additional route(s) omitted for readability.

README topics

  • Layout
  • Demo seeder
  • Naming
  • Migration history

Operating Implications

  • Permission coverage is part of the module contract, so every workflow should be tested with a role-limited user and an administrator.
  • The module has migrations, so fresh installs and tenant databases need migration validation before go-live.
  • The module has a public or portal-facing surface, so privacy review and logged-out testing are required.
  • The module has API documentation or routes, so response examples and query filters should stay aligned with user-facing screens.
  • Scheduled jobs can change statuses, notifications, or summaries after users leave the screen; support should check cron status during troubleshooting.
  • Seeders exist for sample or starter data; operators should know whether seeded records are demo-only or operational defaults.

Known Risks from the Manifest

  • The legacy learn_* tables (learn_courses, learn_categories, learn_module, learn_group, learn_exams, learn_questions, learn_choices, learn_discussions, learn_students) ship in the base install schema (install/migration/schema.php). The newer tables (learn_progress, learn_attempts, learn_answers, learn_certificates, learn_university_settings) and the Phase 1 learn_choices audit-block ALTER are MODULE-OWNED migrations under modules/Learn/migrations/ (tracked in the migrations_courses table). Because Tenant_provisioner runs only core migrations, a newly provisioned tenant does NOT receive these tables/columns at provision time - they are applied by `php erpat migrate:latest`/`migrate:modules` (primary DB) and by the Tenancy Bulk/per-tenant Database Migration tools (erpat_run_module_migrations) against each tenant DB. Run a tenant migration pass after enabling Learn so the schema reaches every tenant (same constraint as the Production and Warehouse module-owned tables).
  • The public /university providers directory reads DENORMALIZED columns on the main-DB clients registry - public_course_count, public_learning_meta and public_learning_categories - so a public page hit never scans each tenant DB. These are CORE migrations (application/migrations/, main DB only; NOT module-owned, per the module-files G5 boundary): 20260704062702_add_public_course_count_to_clients.php and 20260704125247_add_public_learning_meta_to_clients.php. They are maintained live by learn_sync_public_course_count() (University_settings::save, Courses::save/update_status/delete) and reconciled by the SyncPublicCatalogCountJob cron. After migrating, run `php erpat cron:run sync_public_catalog_count` to backfill; the directory cards degrade to name+count until a sync has run for each tenant.
Was this guide helpful?

Report a content problem