feat(core-edu): 完整实现 core-edu 教学核心服务

包含 classes/exams/homework/grades/attendance/scheduling 域、outbox、iam-consumer、redis 配置等完整实现
This commit is contained in:
SpecialX
2026-07-10 19:08:56 +08:00
parent 06a646ea4e
commit 58c0ba1bd9
55 changed files with 4204 additions and 305 deletions

View File

@@ -3,8 +3,17 @@ syntax = "proto3";
package next_edu_cloud.core_edu.v1;
// CoreEdu service contracts - P3 core teaching domain.
// Covers exam management, homework assignment, and grade recording.
// Covers exam management, homework assignment, grade recording,
// attendance tracking, and class queries.
//
// Total: 5 Service / 27 RPC (P3 target state per president-final-rulings §2.5).
// Event contracts live in events.proto under next_edu_cloud.events.v1.
//
// Status naming (ISSUE-003-ai08 arbitration, scheme A):
// ExamStatus: draft / published / in_progress / grading / graded / archived / cancelled
// HomeworkStatus: assigned / submitted / graded
// SubmissionStatus: not_submitted / submitted / graded
// AttendanceStatus: present / absent / late / leave
service ExamService {
rpc CreateExam(CreateExamRequest) returns (CreateExamResponse);
@@ -12,6 +21,9 @@ service ExamService {
rpc ListExamsByClass(ListExamsByClassRequest) returns (ListExamsResponse);
rpc UpdateExam(UpdateExamRequest) returns (UpdateExamResponse);
rpc DeleteExam(DeleteExamRequest) returns (DeleteExamResponse);
rpc PublishExam(PublishExamRequest) returns (PublishExamResponse);
rpc SubmitExam(SubmitExamRequest) returns (SubmitExamResponse);
rpc GradeExam(GradeExamRequest) returns (GradeExamResponse);
}
service HomeworkService {
@@ -19,6 +31,7 @@ service HomeworkService {
rpc GetHomework(GetHomeworkRequest) returns (Homework);
rpc ListHomeworkByClass(ListHomeworkByClassRequest) returns (ListHomeworkResponse);
rpc SubmitHomework(SubmitHomeworkRequest) returns (SubmitHomeworkResponse);
rpc GradeHomework(GradeHomeworkRequest) returns (GradeHomeworkResponse);
}
service GradeService {
@@ -27,54 +40,76 @@ service GradeService {
rpc ListGradesByStudent(ListGradesByStudentRequest) returns (ListGradesResponse);
rpc ListGradesByExam(ListGradesByExamRequest) returns (ListGradesResponse);
rpc ListGradesByHomework(ListGradesByHomeworkRequest) returns (ListGradesResponse);
rpc UpdateGrade(UpdateGradeRequest) returns (UpdateGradeResponse);
}
service ClassService {
rpc GetClass(GetClassRequest) returns (ClassInfo);
rpc GetClassesByTeacher(GetClassesByTeacherRequest) returns (GetClassesByTeacherResponse);
rpc BatchGetClasses(BatchGetClassesRequest) returns (BatchGetClassesResponse);
rpc ListStudentsByClass(ListStudentsByClassRequest) returns (ListStudentsByClassResponse);
}
service AttendanceService {
rpc RecordAttendance(RecordAttendanceRequest) returns (RecordAttendanceResponse);
rpc GetAttendance(GetAttendanceRequest) returns (Attendance);
rpc ListAttendanceByStudent(ListAttendanceByStudentRequest) returns (ListAttendanceResponse);
rpc ListAttendanceByClass(ListAttendanceByClassRequest) returns (ListAttendanceResponse);
}
// ----------------------------------------------------------------------------
// Exam domain
// ----------------------------------------------------------------------------
message Exam {
string id = 1;
string class_id = 2;
string title = 3;
string description = 4;
string exam_date = 5;
string duration = 6;
string total_score = 7;
string status = 8;
string created_by = 9;
string created_at = 10;
string updated_at = 11;
string subject_id = 3;
string title = 4;
string description = 5;
string exam_date = 6; // ISO 8601
int32 duration = 7; // seconds
string total_score = 8; // decimal as string
string status = 9;
string status_changed_at = 10;
string status_changed_by = 11;
string school_id = 12;
string created_by = 13;
string archived_at = 14;
string created_at = 15;
string updated_at = 16;
}
message Homework {
message ExamQuestion {
string id = 1;
string class_id = 2;
string title = 3;
string description = 4;
string due_date = 5;
string status = 6;
string created_by = 7;
string created_at = 8;
string updated_at = 9;
}
message Grade {
string id = 1;
string student_id = 2;
string exam_id = 3;
string homework_id = 4;
string exam_id = 2;
string question_id = 3;
int32 order = 4;
string score = 5;
string feedback = 6;
string question_type = 6;
}
message ExamSubmission {
string id = 1;
string exam_id = 2;
string student_id = 3;
string status = 4;
string submitted_at = 5;
string graded_at = 6;
string graded_by = 7;
string created_at = 8;
string updated_at = 9;
string total_score = 8;
}
message CreateExamRequest {
string class_id = 1;
string title = 2;
string description = 3;
string exam_date = 4;
string duration = 5;
string total_score = 6;
string created_by = 7;
string subject_id = 2;
string title = 3;
string description = 4;
string exam_date = 5;
int32 duration = 6;
string total_score = 7;
string school_id = 8;
string created_by = 9;
}
message CreateExamResponse {
@@ -98,7 +133,7 @@ message UpdateExamRequest {
string title = 2;
string description = 3;
string exam_date = 4;
string duration = 5;
int32 duration = 5;
string total_score = 6;
string status = 7;
}
@@ -115,12 +150,88 @@ message DeleteExamResponse {
bool success = 1;
}
message PublishExamRequest {
string id = 1;
string published_by = 2;
}
message PublishExamResponse {
bool success = 1;
}
message SubmitExamRequest {
string exam_id = 1;
string student_id = 2;
repeated AnswerInput answers = 3;
}
message AnswerInput {
string question_id = 1;
string answer = 2;
}
message SubmitExamResponse {
string submission_id = 1;
}
message GradeExamRequest {
string exam_id = 1;
string submission_id = 2;
repeated ScoreInput scores = 3;
string graded_by = 4;
}
message ScoreInput {
string question_id = 1;
string score = 2;
string teacher_comment = 3;
}
message GradeExamResponse {
bool success = 1;
string total_score = 2;
}
// ----------------------------------------------------------------------------
// Homework domain
// ----------------------------------------------------------------------------
message Homework {
string id = 1;
string class_id = 2;
string subject_id = 3;
string title = 4;
string description = 5;
string due_date = 6;
int32 grace_period = 7;
string status = 8;
string school_id = 9;
string created_by = 10;
string created_at = 11;
string updated_at = 12;
}
message HomeworkSubmission {
string id = 1;
string homework_id = 2;
string student_id = 3;
string status = 4;
string submitted_at = 5;
string graded_at = 6;
string graded_by = 7;
string total_score = 8;
string feedback = 9;
}
message AssignHomeworkRequest {
string class_id = 1;
string title = 2;
string description = 3;
string due_date = 4;
string created_by = 5;
string subject_id = 2;
string title = 3;
string description = 4;
string due_date = 5;
int32 grace_period = 6;
string school_id = 7;
string created_by = 8;
}
message AssignHomeworkResponse {
@@ -140,11 +251,45 @@ message ListHomeworkResponse {
}
message SubmitHomeworkRequest {
string id = 1;
string homework_id = 1;
string student_id = 2;
repeated AnswerInput answers = 3;
}
message SubmitHomeworkResponse {
string submission_id = 1;
}
message GradeHomeworkRequest {
string homework_id = 1;
string submission_id = 2;
repeated ScoreInput scores = 3;
string feedback = 4;
string graded_by = 5;
}
message GradeHomeworkResponse {
bool success = 1;
string total_score = 2;
}
// ----------------------------------------------------------------------------
// Grade domain
// ----------------------------------------------------------------------------
message Grade {
string id = 1;
string student_id = 2;
string exam_id = 3;
string homework_id = 4;
string score = 5;
string total_score = 6;
string feedback = 7;
string graded_by = 8;
string school_id = 9;
string idempotency_key = 10;
string created_at = 11;
string updated_at = 12;
}
message RecordGradeRequest {
@@ -152,8 +297,11 @@ message RecordGradeRequest {
string exam_id = 2;
string homework_id = 3;
string score = 4;
string feedback = 5;
string graded_by = 6;
string total_score = 5;
string feedback = 6;
string graded_by = 7;
string school_id = 8;
string idempotency_key = 9;
}
message RecordGradeResponse {
@@ -179,3 +327,107 @@ message ListGradesByHomeworkRequest {
message ListGradesResponse {
repeated Grade grades = 1;
}
message UpdateGradeRequest {
string id = 1;
string score = 2;
string feedback = 3;
string updated_by = 4;
}
message UpdateGradeResponse {
bool success = 1;
}
// ----------------------------------------------------------------------------
// Class domain (merged from classes service per ISSUE-006 decision #1)
// ----------------------------------------------------------------------------
message ClassInfo {
string id = 1;
string name = 2;
string grade_id = 3;
string head_teacher_id = 4;
string description = 5;
string created_at = 6;
string updated_at = 7;
}
message StudentInfo {
string id = 1;
string name = 2;
string class_id = 3;
}
message GetClassRequest {
string id = 1;
}
message GetClassesByTeacherRequest {
string teacher_id = 1;
}
message GetClassesByTeacherResponse {
repeated ClassInfo classes = 1;
}
message BatchGetClassesRequest {
repeated string ids = 1;
}
message BatchGetClassesResponse {
repeated ClassInfo classes = 1;
}
message ListStudentsByClassRequest {
string class_id = 1;
}
message ListStudentsByClassResponse {
repeated StudentInfo students = 1;
}
// ----------------------------------------------------------------------------
// Attendance domain
// ----------------------------------------------------------------------------
message Attendance {
string id = 1;
string schedule_id = 2;
string student_id = 3;
string status = 4;
string remark = 5;
string recorded_by = 6;
string school_id = 7;
string created_at = 8;
string updated_at = 9;
}
message RecordAttendanceRequest {
string schedule_id = 1;
string student_id = 2;
string status = 3;
string remark = 4;
string recorded_by = 5;
string school_id = 6;
}
message RecordAttendanceResponse {
string id = 1;
}
message GetAttendanceRequest {
string id = 1;
}
message ListAttendanceByStudentRequest {
string student_id = 1;
}
message ListAttendanceByClassRequest {
string class_id = 1;
}
message ListAttendanceResponse {
repeated Attendance attendance = 1;
}

View File

@@ -4,13 +4,36 @@ package next_edu_cloud.events.v1;
// Cross-service event contracts published by CoreEdu via the transactional
// outbox pattern and consumed by downstream services (notifications, analytics,
// audit, etc.). Topics follow the convention edu.{domain}.events.
// audit, etc.).
//
// Topic naming follows the arbitration in coord-cross-review §3.1:
// edu.teaching.<aggregate>.<action>
//
// Event routing (TOPIC_MAP in outbox.publisher.ts):
// edu.exam.events <- exam.created / exam.updated / exam.deleted
// edu.homework.events <- homework.assigned / homework.submitted / homework.graded
// edu.grade.events <- grade.recorded / grade.updated
// edu.class.events <- class.transferred
// edu.teaching.exam.created <- ExamEvent.created
// edu.teaching.exam.updated <- ExamEvent.updated
// edu.teaching.exam.published <- ExamEvent.published
// edu.teaching.exam.submitted <- ExamEvent.submitted
// edu.teaching.exam.deleted <- ExamEvent.deleted
// edu.teaching.homework.assigned <- HomeworkEvent.assigned
// edu.teaching.homework.submitted <- HomeworkEvent.submitted
// edu.teaching.homework.graded <- HomeworkEvent.graded
// edu.teaching.grade.recorded <- GradeEvent.recorded
// edu.teaching.grade.updated <- GradeEvent.updated
// edu.teaching.attendance.recorded <- AttendanceEvent.recorded
// edu.teaching.class.transferred <- ClassEvent.transferred
//
// All events MUST include:
// - schema_version: event schema version (default "v1")
// - event_id: UUID for idempotent consumption
// - occurred_at: business timestamp (ms epoch)
// - metadata: { traceId, userId }
message EventMetadata {
string schema_version = 1;
string trace_id = 2;
string user_id = 3;
}
message ClassEvent {
string event_id = 1;
@@ -20,7 +43,7 @@ message ClassEvent {
string class_id = 5;
string name = 6;
string action = 7;
map<string, string> metadata = 8;
EventMetadata metadata = 8;
}
message ExamEvent {
@@ -30,9 +53,10 @@ message ExamEvent {
int64 occurred_at = 4;
string exam_id = 5;
string class_id = 6;
string title = 7;
string action = 8;
map<string, string> metadata = 9;
string subject_id = 7;
string title = 8;
string action = 9;
EventMetadata metadata = 10;
}
message HomeworkEvent {
@@ -42,9 +66,10 @@ message HomeworkEvent {
int64 occurred_at = 4;
string homework_id = 5;
string class_id = 6;
string title = 7;
string action = 8;
map<string, string> metadata = 9;
string subject_id = 7;
string title = 8;
string action = 9;
EventMetadata metadata = 10;
}
message GradeEvent {
@@ -55,6 +80,19 @@ message GradeEvent {
string grade_id = 5;
string student_id = 6;
string score = 7;
string action = 8;
map<string, string> metadata = 9;
string total_score = 8;
string action = 9;
EventMetadata metadata = 10;
}
message AttendanceEvent {
string event_id = 1;
string aggregate_id = 2;
string event_type = 3;
int64 occurred_at = 4;
string attendance_id = 5;
string schedule_id = 6;
string student_id = 7;
string status = 8;
EventMetadata metadata = 9;
}