feat(cohorts): rename Programs to Cohorts with data migration (#694)

* feat(cohorts): rename Programs to Cohorts with data migration

- Add cohort database tables and Drizzle migration alongside legacy program tables
- Introduce migrate-programs-to-cohorts script to copy existing program data safely
- Rename API routes (/cohort), services, queries, validation, and error codes
- Rename dashboard feature module, routes (/cohorts), navigation, and translations
- Update docs, emails, and internal compliance cron endpoints for cohort terminology
- Keep legacy program tables in place for rollback until explicitly removed

Co-authored-by: Rotimi Best <[email protected]>

* fix(db): restore migrate:answer-data script alongside cohort migration

Co-authored-by: Rotimi Best <[email protected]>

* fix(db): cast program enums when migrating data to cohort tables

Co-authored-by: Rotimi Best <[email protected]>

* fix(db): truncate cohort tables before program-to-cohort copy

Co-authored-by: Rotimi Best <[email protected]>

* fix(db): report accurate row counts in programs-to-cohorts migration

Co-authored-by: Rotimi Best <[email protected]>

---------

Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
Rotimi Best
2026-07-02 12:10:31 +01:00
committed by GitHub
co-authored by Rotimi Best Cursor Agent
parent fe9f8c441f
commit ec61bfe7d9
115 changed files with 19703 additions and 6046 deletions
+8 -8
View File
@@ -1,17 +1,17 @@
import {
searchLmsCourses,
searchLmsPrograms,
searchLmsCohorts,
searchOrgAudience,
searchOrgCourses,
searchOrgPrograms,
searchOrgCohorts,
searchOrgTagsAndGroups,
searchOrgWidgets
} from '@cio/db/queries';
export async function searchOrganization(orgId: string, search: string, limit: number) {
const [courses, programs, widgets, tags, audience] = await Promise.all([
const [courses, cohorts, widgets, tags, audience] = await Promise.all([
searchOrgCourses(orgId, search, limit),
searchOrgPrograms(orgId, search, limit),
searchOrgCohorts(orgId, search, limit),
searchOrgWidgets(orgId, search, limit),
searchOrgTagsAndGroups(orgId, search, limit),
searchOrgAudience(orgId, search, limit)
@@ -19,7 +19,7 @@ export async function searchOrganization(orgId: string, search: string, limit: n
return {
courses,
programs,
cohorts,
widgets,
tags,
audience
@@ -27,13 +27,13 @@ export async function searchOrganization(orgId: string, search: string, limit: n
}
export async function searchLmsOrganization(orgId: string, profileId: string, search: string, limit: number) {
const [courses, programs] = await Promise.all([
const [courses, cohorts] = await Promise.all([
searchLmsCourses(orgId, profileId, search, limit),
searchLmsPrograms(orgId, profileId, search, limit)
searchLmsCohorts(orgId, profileId, search, limit)
]);
return {
courses,
programs
cohorts
};
}