chore(teacher-bff): merge teacher-bff full implementation into main
This commit is contained in:
452
packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql
Normal file
452
packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql
Normal file
@@ -0,0 +1,452 @@
|
||||
# teacher-bff GraphQL Schema (SDL-first, president §2.17)
|
||||
# 版本:v1(P2 第一版,coord 仲裁)
|
||||
# 负责人:ai03
|
||||
# 关联:contracts/teacher-bff_contract.md §1.3、workline §3.1
|
||||
#
|
||||
# 设计原则(02-architecture-design.md §5.1):
|
||||
# 1. 按教学场景域组织(不按角色分),教导主任/教研组长复用同一 schema
|
||||
# 2. Query 为主,Mutation 谨慎(BFF 偏读多写少)
|
||||
# 3. N+1 防御:所有 list 字段经 DataLoader(P4 全量接入)
|
||||
# 4. 复杂度限制:depth ≤ 7,query cost ≤ 1000
|
||||
# 5. admin 命名空间预留(president §5.1:P2 预留 schema,P6 实现 Resolver)
|
||||
#
|
||||
# 错误响应格式:GraphQL errors 数组 + extensions.code = BFF_TEACHER_* + extensions.traceId
|
||||
# 降级模式 B(president §2.6):success=true + error=null + data 内 degraded 字段
|
||||
#
|
||||
# 阶段标注:
|
||||
# P2 = 当前实现(iam gRPC,未启用字段返 null + extensions.warning = "field_unavailable_in_p2")
|
||||
# P3+ = 跨阶段扩展例外(president §2.3),Resolver 内逐步补 gRPC 调用
|
||||
|
||||
scalar DateTime
|
||||
|
||||
# ============ Types ============
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
email: String!
|
||||
name: String!
|
||||
roles: [String!]!
|
||||
permissions: [String!]!
|
||||
dataScope: DataScope!
|
||||
}
|
||||
|
||||
enum DataScope {
|
||||
SELF
|
||||
CLASS
|
||||
GRADE
|
||||
SCHOOL
|
||||
DISTRICT
|
||||
ALL
|
||||
}
|
||||
|
||||
type ViewportItem {
|
||||
key: String!
|
||||
label: String!
|
||||
route: String!
|
||||
icon: String
|
||||
sortOrder: String!
|
||||
requiredPermission: String
|
||||
}
|
||||
|
||||
type Class {
|
||||
id: ID!
|
||||
name: String!
|
||||
gradeId: String!
|
||||
# 延迟加载:班级下的考试(P3+ core-edu gRPC)
|
||||
exams: [Exam!]!
|
||||
# 延迟加载:班级下的作业(P3+ core-edu gRPC)
|
||||
homework: [Homework!]!
|
||||
}
|
||||
|
||||
type Exam {
|
||||
id: ID!
|
||||
title: String!
|
||||
classId: ID!
|
||||
status: ExamStatus!
|
||||
publishedAt: DateTime
|
||||
# 延迟加载:考试下的成绩(P3+ core-edu gRPC)
|
||||
grades: [Grade!]!
|
||||
}
|
||||
|
||||
enum ExamStatus {
|
||||
DRAFT
|
||||
PUBLISHED
|
||||
IN_PROGRESS
|
||||
GRADING
|
||||
SCORED
|
||||
ARCHIVED
|
||||
}
|
||||
|
||||
type Homework {
|
||||
id: ID!
|
||||
title: String!
|
||||
classId: ID!
|
||||
dueDate: DateTime!
|
||||
submissions: [Submission!]!
|
||||
}
|
||||
|
||||
type Submission {
|
||||
id: ID!
|
||||
studentId: ID!
|
||||
submittedAt: DateTime!
|
||||
status: SubmissionStatus!
|
||||
}
|
||||
|
||||
enum SubmissionStatus {
|
||||
NOT_SUBMITTED
|
||||
SUBMITTED
|
||||
GRADED
|
||||
}
|
||||
|
||||
type Grade {
|
||||
id: ID!
|
||||
examId: ID!
|
||||
studentId: ID!
|
||||
score: Float!
|
||||
rank: Int
|
||||
submittedAt: DateTime!
|
||||
}
|
||||
|
||||
type DashboardStats {
|
||||
totalExams: Int
|
||||
pendingGrading: Int
|
||||
todayHomework: Int
|
||||
}
|
||||
|
||||
# Dashboard 聚合数据(P2: iam gRPC 用户基础信息,stats/classes 为 null + warning)
|
||||
type DashboardData {
|
||||
user: User
|
||||
classes: [Class!]!
|
||||
viewports: [ViewportItem!]!
|
||||
stats: DashboardStats
|
||||
}
|
||||
|
||||
# ============ Query ============
|
||||
# P2 核心 5 Query(workline §3.2):dashboard / viewports / me / classes / class
|
||||
|
||||
type Query {
|
||||
# 仪表盘聚合(P2: iam gRPC;P3+: + core-edu + data-ana)
|
||||
# @dataScope: OWN
|
||||
dashboard: DashboardData!
|
||||
|
||||
# 视口配置(L1 导航,iam.GetViewports)
|
||||
viewports: [ViewportItem!]!
|
||||
|
||||
# 当前用户信息(iam.GetUserInfo + GetEffectivePermissions)
|
||||
me: User!
|
||||
|
||||
# 教师班级列表(P2: iam 数据;P3+: core-edu.GetClassesByTeacher)
|
||||
# @dataScope: OWN
|
||||
classes: [Class!]!
|
||||
|
||||
# 单个班级详情(P3+: core-edu)
|
||||
# @permission: CLASS_READ
|
||||
# @dataScope: OWN
|
||||
class(id: ID!): Class
|
||||
|
||||
# ===== P3+ 跨阶段扩展(core-edu gRPC,按 §2.3 跨阶段扩展例外新增)=====
|
||||
|
||||
# 班级下的考试列表(P3: core-edu.ExamService.ListExamsByClass)
|
||||
# @permission: EXAM_READ
|
||||
# @dataScope: OWN
|
||||
exams(classId: ID!): [Exam!]!
|
||||
|
||||
# 班级下的作业列表(P3: core-edu.HomeworkService.ListHomeworkByClass)
|
||||
# @permission: HOMEWORK_READ
|
||||
# @dataScope: OWN
|
||||
homework(classId: ID!): [Homework!]!
|
||||
|
||||
# 考试下的成绩列表(P3: core-edu.GradeService.ListGradesByExam)
|
||||
# @permission: GRADE_READ
|
||||
# @dataScope: OWN
|
||||
grades(examId: ID!): [Grade!]!
|
||||
|
||||
# ===== P4+ 跨阶段扩展(content + data-ana gRPC)=====
|
||||
|
||||
# 知识图谱学习路径(P4: content.KnowledgeGraphService.GetLearningPath)
|
||||
knowledgePath(knowledgePointId: ID!): KnowledgePath!
|
||||
|
||||
# 班级成绩分析(P4: data-ana.AnalyticsService.GetClassPerformance)
|
||||
# @permission: ANALYTICS_TEACHER_DASHBOARD
|
||||
classPerformance(classId: ID!): ClassPerformance!
|
||||
|
||||
# 学生薄弱点(P4: data-ana.AnalyticsService.GetStudentWeakness)
|
||||
studentWeakness(studentId: ID!): StudentWeakness!
|
||||
|
||||
# 学习趋势(P4: data-ana.AnalyticsService.GetLearningTrend)
|
||||
learningTrend(studentId: ID!, dateRange: DateRangeInput): LearningTrend!
|
||||
|
||||
# ===== P5+ 跨阶段扩展(ai + msg gRPC)=====
|
||||
|
||||
# 教师通知列表(P5: msg.NotificationService.ListNotifications)
|
||||
notifications(unreadOnly: Boolean): [Notification!]!
|
||||
|
||||
# ===== admin 命名空间(president §5.1:P2 预留 schema,P6 实现 Resolver)=====
|
||||
# admin-portal 复用 teacher-bff GraphQL endpoint,admin 操作低 QPS 无需独立 BFF
|
||||
admin: AdminQuery!
|
||||
}
|
||||
|
||||
input DateRangeInput {
|
||||
start: DateTime!
|
||||
end: DateTime!
|
||||
}
|
||||
|
||||
# ============ Mutation ============
|
||||
|
||||
type Mutation {
|
||||
# ===== P3+ 跨阶段扩展(core-edu gRPC 透传)=====
|
||||
|
||||
# 创建考试(P3: core-edu.ExamService.CreateExam)
|
||||
# @permission: EXAM_CREATE
|
||||
createExam(input: CreateExamInput!): Exam!
|
||||
|
||||
# 布置作业(P3: core-edu.HomeworkService.AssignHomework)
|
||||
# @permission: HOMEWORK_ASSIGN
|
||||
assignHomework(input: AssignHomeworkInput!): Homework!
|
||||
|
||||
# 录入成绩(P3: core-edu.GradeService.RecordGrade)
|
||||
# @permission: GRADE_RECORD
|
||||
recordGrade(input: RecordGradeInput!): Grade!
|
||||
|
||||
# ===== P5+ 跨阶段扩展(ai + msg gRPC)=====
|
||||
|
||||
# AI 出题(P5: ai.AiService.GenerateQuestion)
|
||||
generateQuestion(input: GenerateQuestionInput!): GeneratedQuestion!
|
||||
|
||||
# 标记通知已读(P5: msg.NotificationService.MarkAsRead)
|
||||
markNotificationAsRead(id: ID!): Notification!
|
||||
|
||||
# ===== admin 命名空间 Mutation(president §5.1:P2 预留,P6 实现)=====
|
||||
admin: AdminMutation!
|
||||
}
|
||||
|
||||
input CreateExamInput {
|
||||
classId: ID!
|
||||
title: String!
|
||||
subject: String!
|
||||
scheduledAt: DateTime!
|
||||
}
|
||||
|
||||
input AssignHomeworkInput {
|
||||
classId: ID!
|
||||
title: String!
|
||||
dueDate: DateTime!
|
||||
}
|
||||
|
||||
input RecordGradeInput {
|
||||
examId: ID!
|
||||
studentId: ID!
|
||||
score: Float!
|
||||
}
|
||||
|
||||
input GenerateQuestionInput {
|
||||
subject: String!
|
||||
gradeLevel: String!
|
||||
difficulty: String!
|
||||
knowledgePointIds: [ID!]!
|
||||
}
|
||||
|
||||
# ============ P4+ 类型(content + data-ana)============
|
||||
|
||||
type KnowledgePath {
|
||||
knowledgePointId: ID!
|
||||
name: String!
|
||||
prerequisites: [KnowledgePoint!]!
|
||||
}
|
||||
|
||||
type KnowledgePoint {
|
||||
id: ID!
|
||||
name: String!
|
||||
subject: String!
|
||||
}
|
||||
|
||||
type ClassPerformance {
|
||||
classId: ID!
|
||||
averageScore: Float!
|
||||
passRate: Float!
|
||||
weaknessTopics: [String!]!
|
||||
}
|
||||
|
||||
type StudentWeakness {
|
||||
studentId: ID!
|
||||
weakTopics: [String!]!
|
||||
recommendedExercises: [String!]!
|
||||
}
|
||||
|
||||
type LearningTrend {
|
||||
studentId: ID!
|
||||
trend: [TrendPoint!]!
|
||||
}
|
||||
|
||||
type TrendPoint {
|
||||
date: DateTime!
|
||||
score: Float!
|
||||
}
|
||||
|
||||
# ============ P5+ 类型(ai + msg)============
|
||||
|
||||
type Notification {
|
||||
id: ID!
|
||||
type: NotificationType!
|
||||
title: String!
|
||||
content: String!
|
||||
read: Boolean!
|
||||
createdAt: DateTime!
|
||||
}
|
||||
|
||||
enum NotificationType {
|
||||
SYSTEM
|
||||
EXAM
|
||||
HOMEWORK
|
||||
GRADE
|
||||
ATTENDANCE
|
||||
}
|
||||
|
||||
type GeneratedQuestion {
|
||||
id: ID!
|
||||
subject: String!
|
||||
difficulty: String!
|
||||
content: String!
|
||||
answer: String!
|
||||
}
|
||||
|
||||
# ============ admin 命名空间(president §5.1:P2 预留 schema,P6 实现 Resolver)============
|
||||
# P2: 类型声明占位,Resolver 返 null(不阻塞 admin-portal schema 内省)
|
||||
# P6: ai03 实现 admin Resolver 真实数据(用户/角色/学校/组织/审计日志管理)
|
||||
|
||||
type AdminQuery {
|
||||
# 用户管理
|
||||
users(page: Int = 1, pageSize: Int = 20): AdminUserPage
|
||||
user(id: ID!): AdminUser
|
||||
|
||||
# 角色权限管理
|
||||
roles: [AdminRole!]!
|
||||
role(id: ID!): AdminRole
|
||||
|
||||
# 学校设置
|
||||
school: AdminSchool
|
||||
|
||||
# 组织管理
|
||||
organizations: [AdminOrganization!]!
|
||||
|
||||
# 审计日志查询
|
||||
auditLogs(page: Int = 1, pageSize: Int = 20): AuditLogPage
|
||||
}
|
||||
|
||||
type AdminMutation {
|
||||
createUser(input: AdminCreateUserInput!): AdminUser!
|
||||
updateUser(id: ID!, input: AdminUpdateUserInput!): AdminUser!
|
||||
deleteUser(id: ID!): Boolean!
|
||||
|
||||
createRole(input: AdminCreateRoleInput!): AdminRole!
|
||||
updateRole(id: ID!, input: AdminUpdateRoleInput!): AdminRole!
|
||||
deleteRole(id: ID!): Boolean!
|
||||
|
||||
updateSchool(input: AdminUpdateSchoolInput!): AdminSchool!
|
||||
|
||||
createOrganization(input: AdminCreateOrganizationInput!): AdminOrganization!
|
||||
updateOrganization(id: ID!, input: AdminUpdateOrganizationInput!): AdminOrganization!
|
||||
deleteOrganization(id: ID!): Boolean!
|
||||
}
|
||||
|
||||
type AdminUser {
|
||||
id: ID!
|
||||
email: String!
|
||||
name: String!
|
||||
roles: [String!]!
|
||||
status: String!
|
||||
createdAt: DateTime!
|
||||
lastLoginAt: DateTime
|
||||
}
|
||||
|
||||
type AdminUserPage {
|
||||
edges: [AdminUser!]!
|
||||
totalCount: Int!
|
||||
page: Int!
|
||||
pageSize: Int!
|
||||
}
|
||||
|
||||
type AdminRole {
|
||||
id: ID!
|
||||
name: String!
|
||||
description: String
|
||||
permissions: [String!]!
|
||||
userCount: Int!
|
||||
}
|
||||
|
||||
type AdminSchool {
|
||||
id: ID!
|
||||
name: String!
|
||||
address: String
|
||||
phone: String
|
||||
studentCount: Int!
|
||||
teacherCount: Int!
|
||||
classCount: Int!
|
||||
}
|
||||
|
||||
type AdminOrganization {
|
||||
id: ID!
|
||||
name: String!
|
||||
type: String!
|
||||
parentId: ID
|
||||
createdAt: DateTime!
|
||||
}
|
||||
|
||||
type AuditLogPage {
|
||||
edges: [AuditLog!]!
|
||||
totalCount: Int!
|
||||
page: Int!
|
||||
pageSize: Int!
|
||||
}
|
||||
|
||||
type AuditLog {
|
||||
id: ID!
|
||||
actorUserId: ID!
|
||||
action: String!
|
||||
resourceType: String!
|
||||
resourceId: ID
|
||||
occurredAt: DateTime!
|
||||
ip: String
|
||||
}
|
||||
|
||||
input AdminCreateUserInput {
|
||||
email: String!
|
||||
name: String!
|
||||
roleIds: [ID!]!
|
||||
}
|
||||
|
||||
input AdminUpdateUserInput {
|
||||
name: String
|
||||
roleIds: [ID!]
|
||||
status: String
|
||||
}
|
||||
|
||||
input AdminCreateRoleInput {
|
||||
name: String!
|
||||
description: String
|
||||
permissions: [String!]!
|
||||
}
|
||||
|
||||
input AdminUpdateRoleInput {
|
||||
name: String
|
||||
description: String
|
||||
permissions: [String!]
|
||||
}
|
||||
|
||||
input AdminUpdateSchoolInput {
|
||||
name: String
|
||||
address: String
|
||||
phone: String
|
||||
}
|
||||
|
||||
input AdminCreateOrganizationInput {
|
||||
name: String!
|
||||
type: String!
|
||||
parentId: ID
|
||||
}
|
||||
|
||||
input AdminUpdateOrganizationInput {
|
||||
name: String
|
||||
type: String
|
||||
parentId: ID
|
||||
}
|
||||
Reference in New Issue
Block a user