// Large-course mode API — learner-facing course manifest (L2, public read). // // GET /api/learn/courses/:courseId // // Static data: the published course framework + per-module courseware ids. // Zero LLM — the learner course page uses this to render the module list and // link each module into the existing /learn/:coursewareId player. import { type NextRequest } from 'next/server'; import { apiError, apiSuccess, API_ERROR_CODES } from '@/lib/server/api-response'; import { createLogger } from '@/lib/logger'; import { courseManifestRepo } from '@/lib/course-manifest-repo/store'; import { isValidCourseManifestId } from '@/lib/course-manifest-repo/store'; import { isPinnedCourseManifestModule } from '@/lib/course-manifest-repo/types'; const log = createLogger('Learner Course API'); export async function GET( request: NextRequest, { params }: { params: Promise<{ courseId: string }> }, ) { try { const { courseId } = await params; if (!isValidCourseManifestId(courseId)) { return apiError(API_ERROR_CODES.INVALID_REQUEST, 400, `Invalid course id: ${courseId}`); } const versionParam = new URL(request.url).searchParams.get('version'); let record; if (versionParam !== null) { const version = Number(versionParam); if (!Number.isInteger(version) || version < 1) { return apiError(API_ERROR_CODES.INVALID_REQUEST, 400, 'Invalid course manifest version'); } record = await courseManifestRepo.getRecord(courseId, version); } else { record = await courseManifestRepo.getLatestRecord(courseId); } if (!record) { return apiError(API_ERROR_CODES.INVALID_REQUEST, 404, `Course not found: ${courseId}`); } if (record.schemaVersion !== 2 || !record.modules.every(isPinnedCourseManifestModule)) { return apiError( API_ERROR_CODES.INVALID_REQUEST, 409, 'This legacy course manifest must be republished before learners can open it', ); } return apiSuccess({ course: { courseId: record.courseId, version: record.version, title: record.title, summary: record.summary, language: record.language, publishedAt: record.publishedAt, modules: record.modules.map((m) => ({ index: m.index, title: m.title, description: m.description, coursewareId: m.coursewareId, coursewareVersion: m.coursewareVersion, contentHash: m.contentHash, })), }, }); } catch (error) { log.error('Learner course manifest failed:', error); return apiError(API_ERROR_CODES.INTERNAL_ERROR, 500, 'Failed to load course'); } }