chore: establish learning module baseline
This commit is contained in:
commit
2d04197f3f
2409 files changed
+533050
No files matched your search
@@ -0,0 +1,79 @@
|
||||
// Large-course mode API — confirm the framework and start module generation.
|
||||
//
|
||||
// POST /api/courses/:courseId/start
|
||||
//
|
||||
// The two-layer flow is deliberately gated: creating a course only generates
|
||||
// the framework (status `framework_ready`). This endpoint is the operator's
|
||||
// explicit confirmation after reviewing the framework — only then does the
|
||||
// Layer-2 single-courseware agent start generating each module one by one.
|
||||
|
||||
import { after, type NextRequest } from 'next/server';
|
||||
import { apiError, apiSuccess, API_ERROR_CODES } from '@/lib/server/api-response';
|
||||
import { buildRequestOrigin } from '@/lib/server/classroom-storage';
|
||||
import { createLogger } from '@/lib/logger';
|
||||
import { isValidCourseId, readCourseRecordReconciled } from '@/lib/course-framework/store';
|
||||
import {
|
||||
isCourseGenerationRunning,
|
||||
runCourseModuleGeneration,
|
||||
} from '@/lib/course-framework/runner';
|
||||
import { requireOpsAccess } from '@/lib/server/ops-access';
|
||||
import {
|
||||
CourseMutationInProgressError,
|
||||
isCoursePublishing,
|
||||
} from '@/lib/course-framework/publish-state';
|
||||
|
||||
const log = createLogger('Course Start API');
|
||||
|
||||
export async function POST(
|
||||
req: NextRequest,
|
||||
{ params }: { params: Promise<{ courseId: string }> },
|
||||
) {
|
||||
const denied = requireOpsAccess(req);
|
||||
if (denied) return denied;
|
||||
|
||||
try {
|
||||
const { courseId } = await params;
|
||||
if (!isValidCourseId(courseId)) {
|
||||
return apiError(API_ERROR_CODES.INVALID_REQUEST, 400, `Invalid course id: ${courseId}`);
|
||||
}
|
||||
const record = await readCourseRecordReconciled(courseId);
|
||||
if (!record) {
|
||||
return apiError(API_ERROR_CODES.INVALID_REQUEST, 404, `Course not found: ${courseId}`);
|
||||
}
|
||||
if (!record.framework) {
|
||||
return apiError(API_ERROR_CODES.INVALID_REQUEST, 409, '课程框架尚未生成,请等待框架生成完成');
|
||||
}
|
||||
if (record.status !== 'framework_ready') {
|
||||
return apiError(
|
||||
API_ERROR_CODES.INVALID_REQUEST,
|
||||
409,
|
||||
`当前状态(${record.status})不允许启动模块生成`,
|
||||
);
|
||||
}
|
||||
if (
|
||||
isCourseGenerationRunning(courseId) ||
|
||||
isCoursePublishing(courseId) ||
|
||||
record.modules.some((m) => m.status === 'generating')
|
||||
) {
|
||||
return apiError(API_ERROR_CODES.INVALID_REQUEST, 409, '该课程已有生成任务正在运行');
|
||||
}
|
||||
|
||||
const baseUrl = buildRequestOrigin(req);
|
||||
const run = runCourseModuleGeneration(courseId, baseUrl);
|
||||
after(() => run);
|
||||
|
||||
log.info(`Course ${courseId}: framework confirmed by operator — starting module generation`);
|
||||
return apiSuccess({
|
||||
courseId,
|
||||
status: 'generating',
|
||||
message: '模块生成已开始',
|
||||
detailUrl: `${baseUrl}/api/courses/${courseId}`,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof CourseMutationInProgressError) {
|
||||
return apiError(API_ERROR_CODES.INVALID_REQUEST, 409, error.message);
|
||||
}
|
||||
log.error('Course start failed:', error);
|
||||
return apiError(API_ERROR_CODES.INTERNAL_ERROR, 500, 'Failed to start module generation');
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user