From 5e8188fbd3e527e8ab54fecc361b1d4eed87b6ca Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Mon, 13 Jul 2026 02:09:57 +0100 Subject: [PATCH] fix: replace stale program references (#749) --- apps/api/src/middlewares/cohort-member.ts | 2 +- .../cohort-newsfeed-comment-author-or-team.ts | 2 +- .../api/src/middlewares/cohort-team-member.ts | 6 +- apps/api/src/routes/cohort/cohort.ts | 30 +++--- apps/api/src/services/cohort/cohort.ts | 20 ++-- apps/api/src/services/cohort/goal.ts | 6 +- apps/api/src/services/cohort/invite.ts | 8 +- apps/dashboard/ROUTE-SPLITTING.md | 2 +- .../lib/features/cohort/api/cohort.svelte.ts | 4 +- .../features/cohort/api/newsfeed.svelte.ts | 4 +- .../components/create-cohort-modal.svelte | 4 +- .../src/lib/utils/translations/da.json | 93 ++++++++-------- .../src/lib/utils/translations/de.json | 99 +++++++++-------- .../src/lib/utils/translations/en.json | 2 +- .../src/lib/utils/translations/es.json | 99 +++++++++-------- .../src/lib/utils/translations/fr.json | 99 +++++++++-------- .../src/lib/utils/translations/hi.json | 101 +++++++++--------- .../src/lib/utils/translations/pl.json | 93 ++++++++-------- .../src/lib/utils/translations/pt.json | 99 +++++++++-------- .../src/lib/utils/translations/ru.json | 101 +++++++++--------- .../src/lib/utils/translations/vi.json | 101 +++++++++--------- .../(app)/cohorts/[id]/courses/+page.svelte | 2 +- .../(app)/cohorts/[id]/settings/+page.svelte | 20 ++-- .../(app)/org/[slug]/cohorts/+page.svelte | 4 +- apps/docs/public/coolify-01-add-resource.png | Bin 554128 -> 0 bytes apps/docs/public/coolify-01-new-resource.png | Bin 142689 -> 0 bytes apps/docs/public/coolify-02-services.png | Bin 413871 -> 0 bytes apps/docs/public/coolify-03-env-vars.png | Bin 619757 -> 0 bytes apps/docs/public/coolify-04-image-tag.png | Bin 61241 -> 0 bytes .../public/coolify-05-dashboard-domain.png | Bin 411689 -> 0 bytes apps/docs/public/coolify-06-deploy-logs.png | Bin 493084 -> 0 bytes .../programs/lms-programs-placeholder.svg | 4 +- .../programs/program-courses-placeholder.svg | 2 +- .../programs/program-newsfeed-placeholder.svg | 2 +- .../programs/program-people-placeholder.svg | 2 +- .../programs/program-settings-placeholder.svg | 2 +- .../programs/program-sidebar-placeholder.svg | 2 +- .../programs/programs-list-placeholder.svg | 6 +- .../programs-overview-placeholder.svg | 4 +- .../public/railway-01-deploy-template.png | Bin 196262 -> 0 bytes .../public/railway-02-services-overview.png | Bin 228785 -> 0 bytes apps/docs/public/railway-03-jobs-smtp.png | Bin 1346059 -> 0 bytes .../public/railway-04-minio-credentials.png | Bin 1381357 -> 0 bytes apps/docs/public/railway-05-api-config.png | Bin 1366286 -> 0 bytes .../railway-06-api-config-additional.png | Bin 1506603 -> 0 bytes apps/docs/public/railway-07-deploying.png | Bin 1510772 -> 0 bytes .../public/railway-08-first-boot-crash.png | Bin 439014 -> 0 bytes .../public/railway-09-generate-domain.png | Bin 415575 -> 0 bytes .../public/railway-10-redeploy-dashboard.png | Bin 414728 -> 0 bytes apps/docs/public/railway-11-redeploy-api.png | Bin 331579 -> 0 bytes apps/docs/public/railway-12-signup.png | Bin 125649 -> 0 bytes .../lib/components/certificate-mock.svelte | 2 +- apps/website/src/lib/components/hero.svelte | 2 +- .../src/lib/components/vs-help-docs.svelte | 2 +- .../customer-education/+page.svelte | 14 +-- .../(marketing)/partner-training/+page.svelte | 10 +- .../src/routes/automation/+page.svelte | 2 +- 57 files changed, 524 insertions(+), 533 deletions(-) delete mode 100644 apps/docs/public/coolify-01-add-resource.png delete mode 100644 apps/docs/public/coolify-01-new-resource.png delete mode 100644 apps/docs/public/coolify-02-services.png delete mode 100644 apps/docs/public/coolify-03-env-vars.png delete mode 100644 apps/docs/public/coolify-04-image-tag.png delete mode 100644 apps/docs/public/coolify-05-dashboard-domain.png delete mode 100644 apps/docs/public/coolify-06-deploy-logs.png delete mode 100644 apps/docs/public/railway-01-deploy-template.png delete mode 100644 apps/docs/public/railway-02-services-overview.png delete mode 100644 apps/docs/public/railway-03-jobs-smtp.png delete mode 100644 apps/docs/public/railway-04-minio-credentials.png delete mode 100644 apps/docs/public/railway-05-api-config.png delete mode 100644 apps/docs/public/railway-06-api-config-additional.png delete mode 100644 apps/docs/public/railway-07-deploying.png delete mode 100644 apps/docs/public/railway-08-first-boot-crash.png delete mode 100644 apps/docs/public/railway-09-generate-domain.png delete mode 100644 apps/docs/public/railway-10-redeploy-dashboard.png delete mode 100644 apps/docs/public/railway-11-redeploy-api.png delete mode 100644 apps/docs/public/railway-12-signup.png diff --git a/apps/api/src/middlewares/cohort-member.ts b/apps/api/src/middlewares/cohort-member.ts index 99250a19..83b9616b 100644 --- a/apps/api/src/middlewares/cohort-member.ts +++ b/apps/api/src/middlewares/cohort-member.ts @@ -26,7 +26,7 @@ export const cohortMemberMiddleware = async (c: Context, next: Next) => { return c.json( { success: false, - error: 'Program ID is required', + error: 'Cohort ID is required', code: 'COHORT_ID_REQUIRED' }, 400 diff --git a/apps/api/src/middlewares/cohort-newsfeed-comment-author-or-team.ts b/apps/api/src/middlewares/cohort-newsfeed-comment-author-or-team.ts index 8d171647..625be45f 100644 --- a/apps/api/src/middlewares/cohort-newsfeed-comment-author-or-team.ts +++ b/apps/api/src/middlewares/cohort-newsfeed-comment-author-or-team.ts @@ -82,7 +82,7 @@ export const cohortNewsfeedCommentAuthorOrTeamMiddleware = async (c: Context, ne return c.json( { success: false, - error: 'Only the author or program team members can perform this action', + error: 'Only the author or cohort team members can perform this action', code: ErrorCodes.ORG_TEAM_NOT_AUTHORIZED }, 403 diff --git a/apps/api/src/middlewares/cohort-team-member.ts b/apps/api/src/middlewares/cohort-team-member.ts index c885e665..e6e2ac17 100644 --- a/apps/api/src/middlewares/cohort-team-member.ts +++ b/apps/api/src/middlewares/cohort-team-member.ts @@ -6,7 +6,7 @@ import { ROLE } from '@cio/utils/constants'; /** * Middleware to check if the authenticated user is a cohort teacher or org admin. - * Mirrors the course-team-member pattern for program routes. + * Mirrors the course-team-member pattern for cohort routes. */ export const cohortTeamMemberMiddleware = async (c: Context, next: Next) => { try { @@ -27,7 +27,7 @@ export const cohortTeamMemberMiddleware = async (c: Context, next: Next) => { return c.json( { success: false, - error: 'Program ID is required', + error: 'Cohort ID is required', code: 'COHORT_ID_REQUIRED' }, 400 @@ -56,7 +56,7 @@ export const cohortTeamMemberMiddleware = async (c: Context, next: Next) => { return c.json( { success: false, - error: 'Failed to verify program team membership', + error: 'Failed to verify cohort team membership', code: 'COHORT_TEAM_MEMBER_CHECK_FAILED' }, 500 diff --git a/apps/api/src/routes/cohort/cohort.ts b/apps/api/src/routes/cohort/cohort.ts index e5204b64..ed76b74c 100644 --- a/apps/api/src/routes/cohort/cohort.ts +++ b/apps/api/src/routes/cohort/cohort.ts @@ -82,29 +82,29 @@ export const cohortRouter = new Hono() /** * GET /cohort/enrolled - * Get programs the current user is enrolled in + * Get cohorts the current user is enrolled in */ .get('/enrolled', authMiddleware, async (c) => { try { const user = c.get('user')!; - const programs = await getEnrolledCohorts(user.id); - return c.json({ success: true, data: programs }, 200); + const cohorts = await getEnrolledCohorts(user.id); + return c.json({ success: true, data: cohorts }, 200); } catch (error) { return handleError(c, error, 'Failed to get enrolled cohorts'); } }) - // ── Programs ────────────────────────────────────────────────────────────── + // ── Cohorts ─────────────────────────────────────────────────────────────── /** * GET /cohort?organizationId=... - * List all programs for an org + * List all cohorts for an org */ .get('/', authMiddleware, zValidator('query', ZOrgQuery), async (c) => { try { const { organizationId } = c.req.valid('query'); - const programs = await listOrgCohorts(organizationId); - return c.json({ success: true, data: programs }, 200); + const cohorts = await listOrgCohorts(organizationId); + return c.json({ success: true, data: cohorts }, 200); } catch (error) { return handleError(c, error, 'Failed to list cohorts'); } @@ -112,7 +112,7 @@ export const cohortRouter = new Hono() /** * POST /cohort - * Create a new program + * Create a new cohort */ .post( '/', @@ -255,7 +255,7 @@ export const cohortRouter = new Hono() const member = await removeCohortMemberService(cohortId, memberId); return c.json({ success: true, data: member }, 200); } catch (error) { - return handleError(c, error, 'Failed to remove program member'); + return handleError(c, error, 'Failed to remove cohort member'); } } ) @@ -267,7 +267,7 @@ export const cohortRouter = new Hono() * Invite new students to a cohort by CSV emails. Issues org invites * pre-tagged with this cohort so accept auto-enrolls them. * Gated by cohort-team-member middleware — Cohort ADMINs/TUTORs can - * invite into their own program without org-admin rights. + * invite into their own cohort without org-admin rights. */ .post( '/:cohortId/invite', @@ -283,7 +283,7 @@ export const cohortRouter = new Hono() const result = await inviteStudentsToCohort(cohortId, data, user.id); return c.json({ success: true, data: result }, 201); } catch (error) { - return handleError(c, error, 'Failed to invite students to program'); + return handleError(c, error, 'Failed to invite students to cohort'); } } ) @@ -305,7 +305,7 @@ export const cohortRouter = new Hono() const result = await assignExistingStudentsToCohort(cohortId, data); return c.json({ success: true, data: result }, 200); } catch (error) { - return handleError(c, error, 'Failed to assign students to program'); + return handleError(c, error, 'Failed to assign students to cohort'); } } ) @@ -344,7 +344,7 @@ export const cohortRouter = new Hono() const result = await addCourseToCohortService(cohortId, data); return c.json({ success: true, data: result }, 201); } catch (error) { - return handleError(c, error, 'Failed to add course to program'); + return handleError(c, error, 'Failed to add course to cohort'); } } ) @@ -364,7 +364,7 @@ export const cohortRouter = new Hono() const result = await removeCourseFromCohortService(cohortId, courseId); return c.json({ success: true, data: result }, 200); } catch (error) { - return handleError(c, error, 'Failed to remove course from program'); + return handleError(c, error, 'Failed to remove course from cohort'); } } ) @@ -547,7 +547,7 @@ export const cohortRouter = new Hono() /** * GET /cohort/my/goals - * Goal assignments for the current authenticated user across all their programs. + * Goal assignments for the current authenticated user across all their cohorts. * Used by the LMS "Your Goals" widget. */ .get('/my/goals', authMiddleware, async (c) => { diff --git a/apps/api/src/services/cohort/cohort.ts b/apps/api/src/services/cohort/cohort.ts index 26ea1b23..80b83c37 100644 --- a/apps/api/src/services/cohort/cohort.ts +++ b/apps/api/src/services/cohort/cohort.ts @@ -105,11 +105,11 @@ async function enrollCohortStudentsInGroups( return groupMemberRows.length; } -// ─── Program CRUD ──────────────────────────────────────────────────────────── +// ─── Cohort CRUD ───────────────────────────────────────────────────────────── export async function createCohort(organizationId: string, profileId: string, data: TCreateCohort) { try { - const description = data.description?.trim() || `A program for ${data.name}`; + const description = data.description?.trim() || `A cohort for ${data.name}`; return createCohortWithCreatorMembership( { @@ -195,7 +195,7 @@ export async function deleteCohort(cohortId: string) { } } -// ─── Program Members ───────────────────────────────────────────────────────── +// ─── Cohort Members ────────────────────────────────────────────────────────── export async function listCohortMembers(cohortId: string) { try { @@ -323,7 +323,7 @@ export async function removeCohortMemberService(_cohortId: string, memberId: str } catch (error) { if (error instanceof AppError) throw error; throw new AppError( - error instanceof Error ? error.message : 'Failed to remove program member', + error instanceof Error ? error.message : 'Failed to remove cohort member', ErrorCodes.INTERNAL_ERROR, 500 ); @@ -360,7 +360,7 @@ export async function getEnrolledCohorts(profileId: string) { } } -// ─── Program Courses ───────────────────────────────────────────────────────── +// ─── Cohort Courses ────────────────────────────────────────────────────────── export async function listCohortCourses(cohortId: string, profileId: string) { try { @@ -411,7 +411,7 @@ export async function addCourseToCohortService(cohortId: string, data: TAddCours } catch (error) { if (error instanceof AppError) throw error; throw new AppError( - error instanceof Error ? error.message : 'Failed to add course to program', + error instanceof Error ? error.message : 'Failed to add course to cohort', ErrorCodes.INTERNAL_ERROR, 500 ); @@ -422,20 +422,20 @@ export async function removeCourseFromCohortService(cohortId: string, courseId: try { const deleted = await removeCourseFromCohort(cohortId, courseId); if (!deleted) { - throw new AppError('Course not found in program', ErrorCodes.NOT_FOUND, 404); + throw new AppError('Course not found in cohort', ErrorCodes.NOT_FOUND, 404); } return deleted; } catch (error) { if (error instanceof AppError) throw error; throw new AppError( - error instanceof Error ? error.message : 'Failed to remove course from program', + error instanceof Error ? error.message : 'Failed to remove course from cohort', ErrorCodes.INTERNAL_ERROR, 500 ); } } -// ─── Program Newsfeed ──────────────────────────────────────────────────────── +// ─── Cohort Newsfeed ───────────────────────────────────────────────────────── export async function listCohortNewsfeed(cohortId: string, options: { cursor?: string; limit: number }) { try { @@ -524,7 +524,7 @@ export async function deleteCohortNewsfeedService(feedId: string) { } } -// ─── Program Newsfeed Comments ──────────────────────────────────────────────── +// ─── Cohort Newsfeed Comments ──────────────────────────────────────────────── export async function listCohortNewsfeedComments(feedId: string) { try { diff --git a/apps/api/src/services/cohort/goal.ts b/apps/api/src/services/cohort/goal.ts index 8830103a..df3620cc 100644 --- a/apps/api/src/services/cohort/goal.ts +++ b/apps/api/src/services/cohort/goal.ts @@ -221,7 +221,7 @@ function decideStatus(args: { * * Pulls all student cohort-members, computes a per-learner status, and upserts * `program_goal_assignment`. Designed to be safe to run repeatedly (idempotent) - * and cheap enough for daily cron over hundreds of programs. + * and cheap enough for daily cron over hundreds of cohorts. */ export async function evaluateGoal(goalId: string): Promise<{ evaluated: number }> { const goal = await getCohortGoalById(goalId); @@ -316,7 +316,7 @@ export async function evaluateGoal(goalId: string): Promise<{ evaluated: number } /** - * Re-evaluate every active goal in a cohort. Used after material program + * Re-evaluate every active goal in a cohort. Used after material cohort * changes (member added, course added) or by cron sweeps. */ export async function evaluateCohortGoals(cohortId: string): Promise<{ evaluated: number }> { @@ -450,7 +450,7 @@ export async function getMyGoals(profileId: string) { /** * Cross-cohort goal roll-up for the org owner. Lists every active goal in the - * org with its per-status counts so the dashboard can group by program. + * org with its per-status counts so the dashboard can group by cohort. */ export async function getOrgGoalsOverview(organizationId: string) { const goals = await getCohortGoalsByOrg(organizationId); diff --git a/apps/api/src/services/cohort/invite.ts b/apps/api/src/services/cohort/invite.ts index 19d75f9e..41128487 100644 --- a/apps/api/src/services/cohort/invite.ts +++ b/apps/api/src/services/cohort/invite.ts @@ -4,11 +4,11 @@ import type { TInviteStudentsToCohort, TAssignExistingStudentsToCohort } from '@ import { assignAudienceToCourses, importAudienceMembers } from '@api/services/organization/audience'; /** - * Invite students to a single program by email CSV. + * Invite students to a single cohort by email CSV. * * Thin wrapper that hardcodes `cohortIds = [cohortId]` and delegates to * `importAudienceMembers`. Lets a Cohort ADMIN/TUTOR (or org admin) issue org - * invites scoped to *their own* program, without granting org-wide invite rights. + * invites scoped to *their own* cohort, without granting org-wide invite rights. */ export async function inviteStudentsToCohort( cohortId: string, @@ -35,8 +35,8 @@ export async function inviteStudentsToCohort( /** * Assign existing student profiles (already members of the org audience) to a - * single program. Same scoping logic as `inviteStudentsToCohort` — restricted - * to one program at a time so the caller's program-admin permission is enough. + * single cohort. Same scoping logic as `inviteStudentsToCohort` — restricted + * to one cohort at a time so the caller's cohort-admin permission is enough. */ export async function assignExistingStudentsToCohort(cohortId: string, data: TAssignExistingStudentsToCohort) { const cohort = await getCohortById(cohortId); diff --git a/apps/dashboard/ROUTE-SPLITTING.md b/apps/dashboard/ROUTE-SPLITTING.md index 9d1862b4..13c20cdd 100644 --- a/apps/dashboard/ROUTE-SPLITTING.md +++ b/apps/dashboard/ROUTE-SPLITTING.md @@ -31,7 +31,7 @@ routes/ │ ├── courses/ # Course management │ ├── org/ # Org settings │ ├── lms/ # Student LMS -│ ├── programs/ # Programs +│ ├── cohorts/ # Cohorts │ └── home/ # Dashboard home │ ├── (auth)/ # Auth pages (login, signup, etc.) diff --git a/apps/dashboard/src/lib/features/cohort/api/cohort.svelte.ts b/apps/dashboard/src/lib/features/cohort/api/cohort.svelte.ts index d1588b32..3b98ffab 100644 --- a/apps/dashboard/src/lib/features/cohort/api/cohort.svelte.ts +++ b/apps/dashboard/src/lib/features/cohort/api/cohort.svelte.ts @@ -297,7 +297,7 @@ class CohortApi extends BaseApiWithErrors { }); } - // Invitations (program-scoped) + // Invitations (cohort-scoped) /** * Invite new students to a cohort by CSV. Goes through the cohort-scoped @@ -322,7 +322,7 @@ class CohortApi extends BaseApiWithErrors { /** * Assign existing org audience student profiles to this cohort. - * Same scoping as `inviteStudentsToCohort` — caller only needs program-team + * Same scoping as `inviteStudentsToCohort` — caller only needs cohort-team * membership for this cohort. */ async assignExistingStudentsToCohort(cohortId: string, data: TAssignExistingStudentsToCohort): Promise { diff --git a/apps/dashboard/src/lib/features/cohort/api/newsfeed.svelte.ts b/apps/dashboard/src/lib/features/cohort/api/newsfeed.svelte.ts index 549e4651..3ae648d2 100644 --- a/apps/dashboard/src/lib/features/cohort/api/newsfeed.svelte.ts +++ b/apps/dashboard/src/lib/features/cohort/api/newsfeed.svelte.ts @@ -5,9 +5,9 @@ import type { DeleteCohortNewsfeedCommentRequest, DeleteCohortNewsfeedRequest, GetCohortNewsfeedCommentsRequest, + CohortNewsfeedComment, ListCohortNewsfeed, ListCohortNewsfeedRequest, - ProgramNewsfeedComment, ReactToCohortNewsfeedRequest, UpdateCohortNewsfeedRequest } from '../utils/types'; @@ -30,7 +30,7 @@ import { profile } from '$lib/utils/store/user'; import { snackbar } from '$features/ui/snackbar/store'; export type CohortNewsfeedCommentsByFeedId = { - items: ProgramNewsfeedComment[]; + items: CohortNewsfeedComment[]; totalCount: number; hasMore: boolean; isLoading: boolean; diff --git a/apps/dashboard/src/lib/features/cohort/components/create-cohort-modal.svelte b/apps/dashboard/src/lib/features/cohort/components/create-cohort-modal.svelte index b76388e9..8c1df41a 100644 --- a/apps/dashboard/src/lib/features/cohort/components/create-cohort-modal.svelte +++ b/apps/dashboard/src/lib/features/cohort/components/create-cohort-modal.svelte @@ -42,7 +42,7 @@
- +
- +