Files
Edu/packages/shared-ts/contracts/graphql/teacher-bff.schema.graphql
SpecialX 99155a5ea1 feat(teacher-bff): 完整实现 teacher-bff GraphQL 聚合层
包含 clients/graphql/middleware、health probes、shared-ts contracts 等
2026-07-10 19:10:07 +08:00

453 lines
9.7 KiB
GraphQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
}