{ "_meta": { "project": "Next_Edu", "description": "K12 智慧教务管理系统", "generatedAt": "2026-06-16", "formatVersion": "1.0", "rule": "每次文件修改后须同步更新本文件" }, "techStack": { "framework": "Next.js 16 (App Router)", "language": "TypeScript (strict)", "ui": "React 19 + Tailwind CSS v4 + shadcn/ui", "state": ["Zustand", "nuqs", "React Hook Form"], "database": "MySQL + Drizzle ORM 0.45", "auth": "NextAuth v5 (JWT strategy)", "validation": "Zod 4", "ai": "OpenAI SDK (multi-provider)", "testing": ["Vitest", "Playwright"] }, "roles": ["admin", "teacher", "student", "parent", "grade_head", "teaching_head"], "permissions": { "EXAM_CREATE": "exam:create", "EXAM_READ": "exam:read", "EXAM_UPDATE": "exam:update", "EXAM_DELETE": "exam:delete", "EXAM_DUPLICATE": "exam:duplicate", "EXAM_PUBLISH": "exam:publish", "EXAM_AI_GENERATE": "exam:ai_generate", "HOMEWORK_CREATE": "homework:create", "HOMEWORK_GRADE": "homework:grade", "HOMEWORK_SUBMIT": "homework:submit", "QUESTION_CREATE": "question:create", "QUESTION_READ": "question:read", "QUESTION_UPDATE": "question:update", "QUESTION_DELETE": "question:delete", "TEXTBOOK_CREATE": "textbook:create", "TEXTBOOK_READ": "textbook:read", "TEXTBOOK_UPDATE": "textbook:update", "TEXTBOOK_DELETE": "textbook:delete", "CLASS_CREATE": "class:create", "CLASS_READ": "class:read", "CLASS_UPDATE": "class:update", "CLASS_DELETE": "class:delete", "CLASS_ENROLL": "class:enroll", "CLASS_SCHEDULE": "class:schedule", "SCHOOL_MANAGE": "school:manage", "GRADE_MANAGE": "grade:manage", "USER_MANAGE": "user:manage", "AI_CHAT": "ai:chat", "AI_CONFIGURE": "ai:configure", "SETTINGS_ADMIN": "settings:admin", "AUDIT_LOG_READ": "audit_log:read", "ANNOUNCEMENT_MANAGE": "announcement:manage", "ANNOUNCEMENT_READ": "announcement:read", "GRADE_RECORD_MANAGE": "grade_record:manage", "GRADE_RECORD_READ": "grade_record:read", "FILE_UPLOAD": "file:upload", "FILE_READ": "file:read", "FILE_DELETE": "file:delete", "COURSE_PLAN_MANAGE": "course_plan:manage", "COURSE_PLAN_READ": "course_plan:read", "ATTENDANCE_MANAGE": "attendance:manage", "ATTENDANCE_READ": "attendance:read", "MESSAGE_SEND": "message:send", "MESSAGE_READ": "message:read", "MESSAGE_DELETE": "message:delete", "SCHEDULE_AUTO": "schedule:auto", "SCHEDULE_ADJUST": "schedule:adjust", "DIAGNOSTIC_MANAGE": "diagnostic:manage", "DIAGNOSTIC_READ": "diagnostic:read", "ELECTIVE_MANAGE": "elective:manage", "ELECTIVE_READ": "elective:read", "ELECTIVE_SELECT": "elective:select" }, "rolePermissions": { "admin": ["EXAM_CREATE","EXAM_READ","EXAM_UPDATE","EXAM_DELETE","EXAM_DUPLICATE","EXAM_PUBLISH","EXAM_AI_GENERATE","HOMEWORK_CREATE","HOMEWORK_GRADE","QUESTION_CREATE","QUESTION_READ","QUESTION_UPDATE","QUESTION_DELETE","TEXTBOOK_CREATE","TEXTBOOK_READ","TEXTBOOK_UPDATE","TEXTBOOK_DELETE","CLASS_CREATE","CLASS_READ","CLASS_UPDATE","CLASS_DELETE","CLASS_ENROLL","CLASS_SCHEDULE","SCHOOL_MANAGE","GRADE_MANAGE","USER_MANAGE","AI_CHAT","AI_CONFIGURE","SETTINGS_ADMIN","AUDIT_LOG_READ","ANNOUNCEMENT_MANAGE","ANNOUNCEMENT_READ","GRADE_RECORD_MANAGE","GRADE_RECORD_READ","FILE_UPLOAD","FILE_READ","FILE_DELETE","COURSE_PLAN_MANAGE","COURSE_PLAN_READ","ATTENDANCE_MANAGE","ATTENDANCE_READ","MESSAGE_SEND","MESSAGE_READ","MESSAGE_DELETE","SCHEDULE_AUTO","SCHEDULE_ADJUST","DIAGNOSTIC_MANAGE","DIAGNOSTIC_READ","ELECTIVE_MANAGE","ELECTIVE_READ"], "teacher": ["EXAM_CREATE","EXAM_READ","EXAM_UPDATE","EXAM_DELETE","EXAM_DUPLICATE","EXAM_PUBLISH","EXAM_AI_GENERATE","HOMEWORK_CREATE","HOMEWORK_GRADE","QUESTION_CREATE","QUESTION_READ","QUESTION_UPDATE","QUESTION_DELETE","TEXTBOOK_CREATE","TEXTBOOK_READ","TEXTBOOK_UPDATE","CLASS_READ","CLASS_ENROLL","CLASS_SCHEDULE","AI_CHAT","ANNOUNCEMENT_READ","GRADE_RECORD_MANAGE","GRADE_RECORD_READ","FILE_UPLOAD","FILE_READ","FILE_DELETE","COURSE_PLAN_READ","ATTENDANCE_MANAGE","ATTENDANCE_READ","MESSAGE_SEND","MESSAGE_READ","MESSAGE_DELETE","DIAGNOSTIC_MANAGE","DIAGNOSTIC_READ","ELECTIVE_MANAGE","ELECTIVE_READ"], "student": ["EXAM_READ","HOMEWORK_SUBMIT","QUESTION_READ","TEXTBOOK_READ","CLASS_READ","AI_CHAT","ANNOUNCEMENT_READ","GRADE_RECORD_READ","FILE_READ","COURSE_PLAN_READ","ATTENDANCE_READ","MESSAGE_READ","MESSAGE_DELETE","DIAGNOSTIC_READ","ELECTIVE_SELECT","ELECTIVE_READ"], "parent": ["EXAM_READ","TEXTBOOK_READ","CLASS_READ","ANNOUNCEMENT_READ","GRADE_RECORD_READ","FILE_READ","ATTENDANCE_READ","MESSAGE_SEND","MESSAGE_READ","MESSAGE_DELETE"], "grade_head": ["EXAM_CREATE","EXAM_READ","EXAM_UPDATE","EXAM_DELETE","EXAM_DUPLICATE","EXAM_PUBLISH","EXAM_AI_GENERATE","HOMEWORK_CREATE","HOMEWORK_GRADE","QUESTION_CREATE","QUESTION_READ","QUESTION_UPDATE","QUESTION_DELETE","TEXTBOOK_CREATE","TEXTBOOK_READ","TEXTBOOK_UPDATE","CLASS_CREATE","CLASS_READ","CLASS_UPDATE","CLASS_ENROLL","CLASS_SCHEDULE","GRADE_MANAGE","AI_CHAT","ANNOUNCEMENT_READ","GRADE_RECORD_READ","COURSE_PLAN_READ","ATTENDANCE_READ","MESSAGE_SEND","MESSAGE_READ","MESSAGE_DELETE","DIAGNOSTIC_MANAGE","DIAGNOSTIC_READ","ELECTIVE_READ"], "teaching_head": ["EXAM_CREATE","EXAM_READ","EXAM_UPDATE","EXAM_DELETE","EXAM_DUPLICATE","EXAM_PUBLISH","EXAM_AI_GENERATE","HOMEWORK_CREATE","HOMEWORK_GRADE","QUESTION_CREATE","QUESTION_READ","QUESTION_UPDATE","QUESTION_DELETE","TEXTBOOK_CREATE","TEXTBOOK_READ","TEXTBOOK_UPDATE","CLASS_READ","GRADE_MANAGE","AI_CHAT","ANNOUNCEMENT_READ","GRADE_RECORD_READ","COURSE_PLAN_READ","ATTENDANCE_READ","MESSAGE_SEND","MESSAGE_READ","MESSAGE_DELETE","DIAGNOSTIC_READ","ELECTIVE_READ"] }, "dataScopeTypes": { "all": "管理员:无过滤", "owned": "仅自己创建的资源,含 userId 字段", "class_taught": "教师:所教班级,含 classIds[] 和可选 subjectIds[]", "grade_managed": "年级主任:所管年级,含 gradeIds[]", "class_members": "学生:所在班级的成员数据", "children": "家长:子女数据,含 childrenIds[]" }, "modules": { "shared": { "path": "src/shared", "description": "全项目共享基础设施:数据库、工具函数、权限系统、UI组件、Hooks", "exports": { "functions": [ { "name": "cn", "file": "lib/utils.ts", "signature": "cn(...inputs: ClassValue[]): string", "purpose": "合并CSS类名并解决Tailwind冲突", "deps": ["clsx", "tailwind-merge"], "usedBy": ["*所有模块组件"] }, { "name": "formatDate", "file": "lib/utils.ts", "signature": "formatDate(date: string | Date, locale?: string): string", "params": {"date": "日期值", "locale": "Intl locale,默认zh-CN"}, "purpose": "国际化日期格式化", "deps": [], "usedBy": ["exams", "homework", "dashboard", "textbooks"] }, { "name": "parseAiChatPayload", "file": "lib/ai.ts", "signature": "parseAiChatPayload(body: unknown): AiChatRequest", "purpose": "解析并校验AI聊天请求负载", "deps": ["zod"], "usedBy": ["app/api/ai/chat/route.ts"] }, { "name": "encryptAiApiKey", "file": "lib/ai.ts", "signature": "encryptAiApiKey(value: string): string", "purpose": "AES加密AI Provider API Key", "deps": ["crypto"], "usedBy": ["settings/actions.ts"] }, { "name": "decryptAiApiKey", "file": "lib/ai.ts", "signature": "decryptAiApiKey(value: string): string", "purpose": "AES解密AI Provider API Key", "deps": ["crypto"], "usedBy": ["settings/actions.ts", "ai.ts内部"] }, { "name": "testAiProviderConfig", "file": "lib/ai.ts", "signature": "testAiProviderConfig(input: { apiKey: string; baseUrl?: string; model: string }): Promise", "purpose": "测试AI Provider连通性(直接配置)", "deps": ["createAiChatCompletion"], "usedBy": ["settings/actions.ts"] }, { "name": "testAiProviderById", "file": "lib/ai.ts", "signature": "testAiProviderById(providerId: string, overrides?: { baseUrl?: string; model?: string }): Promise", "purpose": "测试AI Provider连通性(按ID)", "deps": ["shared/db", "createAiChatCompletion"], "usedBy": ["settings/actions.ts"] }, { "name": "createAiChatCompletion", "file": "lib/ai.ts", "signature": "createAiChatCompletion(input: AiChatRequest): Promise<{ content: string; usage: unknown }>", "purpose": "调用AI模型生成聊天回复", "deps": ["openai", "shared/db"], "usedBy": ["exams/ai-pipeline.ts", "app/api/ai/chat/route.ts"] }, { "name": "getAiErrorMessage", "file": "lib/ai.ts", "signature": "getAiErrorMessage(v: unknown): string", "purpose": "从AI错误中提取可读消息", "deps": [], "usedBy": ["exams/ai-pipeline.ts"] }, { "name": "getAuthContext", "file": "lib/auth-guard.ts", "signature": "getAuthContext(): Promise", "returns": "AuthContext { userId, roles, permissions, dataScope }", "purpose": "获取当前用户完整认证上下文", "deps": ["auth (NextAuth)", "shared/db"], "usedBy": ["所有业务模块的Server Actions"] }, { "name": "requirePermission", "file": "lib/auth-guard.ts", "signature": "requirePermission(permission: Permission): Promise", "throws": "PermissionDeniedError", "purpose": "断言当前用户拥有指定权限", "deps": ["getAuthContext"], "usedBy": ["所有业务模块的Server Actions"] }, { "name": "checkPermission", "file": "lib/auth-guard.ts", "signature": "checkPermission(permission: Permission): Promise<{ allowed: boolean; ctx: AuthContext }>", "purpose": "非抛出版权限检查", "deps": ["getAuthContext"], "usedBy": [] }, { "name": "requireAuth", "file": "lib/auth-guard.ts", "signature": "requireAuth(): Promise", "purpose": "仅断言用户已登录", "deps": ["getAuthContext"], "usedBy": [] }, { "name": "resolvePermissions", "file": "lib/permissions.ts", "signature": "resolvePermissions(roleNames: string[]): Permission[]", "purpose": "合并多角色的权限列表(去重)", "deps": ["ROLE_PERMISSIONS"], "usedBy": ["auth.ts (JWT callback)"] }, { "name": "logAudit", "file": "lib/audit-logger.ts", "signature": "logAudit(params: LogAuditParams): Promise", "purpose": "记录操作日志(静默失败)", "deps": ["auth", "shared.db", "shared.db.schema.auditLogs", "next/headers"], "usedBy": ["school/actions.ts", "其他Server Actions"] }, { "name": "logLoginEvent", "file": "lib/login-logger.ts", "signature": "logLoginEvent(params: LogLoginEventParams): Promise", "purpose": "记录登录日志(signin/signout/signup,静默失败)", "deps": ["shared.db", "shared.db.schema.loginLogs", "next/headers"], "usedBy": ["auth.ts (events.signIn, events.signOut)"] }, { "name": "isAllowedMimeType", "file": "lib/file-storage.ts", "signature": "isAllowedMimeType(mimeType: string): boolean", "purpose": "判断MIME类型是否在允许上传的白名单中", "deps": ["ALLOWED_MIME_TYPES 常量"], "usedBy": ["app/api/upload/route.ts", "files/components/file-upload.tsx"] }, { "name": "generateStoragePath", "file": "lib/file-storage.ts", "signature": "generateStoragePath(originalName: string): string", "purpose": "根据原始文件名生成存储路径 uploads/YYYY-MM/cuid.ext(相对于public/)", "deps": ["@paralleldrive/cuid2"], "usedBy": ["app/api/upload/route.ts"] }, { "name": "getFileExtension", "file": "lib/file-storage.ts", "signature": "getFileExtension(filename: string): string", "purpose": "从文件名中提取小写扩展名(不含点)", "deps": [], "usedBy": ["shared/lib/file-storage 内部"] }, { "name": "formatFileSize", "file": "lib/file-storage.ts", "signature": "formatFileSize(bytes: number): string", "purpose": "将字节数格式化为人类可读字符串(如 1.5 MB、800 KB)", "deps": [], "usedBy": ["files/components/file-upload.tsx", "files/components/file-list.tsx", "files/components/file-preview.tsx"] }, { "name": "exportToExcel", "file": "lib/excel.ts", "signature": "exportToExcel(params: { sheets: ExcelSheet[] }): Promise", "params": {"sheets": "ExcelSheet[],每个含 name/columns/rows"}, "purpose": "将多 sheet 数据导出为 Excel Buffer(表头加粗+冻结首行+自动筛选)", "deps": ["exceljs"], "usedBy": ["users/import-export.exportUsersToExcel", "grades/export.exportGradeRecordsToExcel", "grades/export.exportClassGradeReportToExcel"] }, { "name": "parseExcel", "file": "lib/excel.ts", "signature": "parseExcel(buffer: Buffer): Promise", "returns": "ParsedSheet[],每个含 sheetName/rows", "purpose": "从 Buffer 解析 Excel 文件,首行作为表头,返回每 sheet 的行记录数组", "deps": ["exceljs"], "usedBy": ["users/actions.importUsersAction", "app/api/import/route.ts"] }, { "name": "generateTemplate", "file": "lib/excel.ts", "signature": "generateTemplate(params: { sheets: TemplateSheet[] }): Promise", "params": {"sheets": "TemplateSheet[],每个含 name/columns(含 note)/sampleRows?"}, "purpose": "生成导入模板 Buffer(表头加粗+第二行填写说明+示例行)", "deps": ["exceljs"], "usedBy": ["users/import-export.generateUserImportTemplate"] } ], "hooks": [ { "name": "useActionWithToast", "file": "hooks/use-action-with-toast.ts", "signature": "useActionWithToast(): { isPending: boolean; execute: (action: () => Promise>) => void }", "purpose": "包装Server Action + toast反馈" }, { "name": "useDebounce", "file": "hooks/use-debounce.ts", "signature": "useDebounce(value: T, delay?: number): T", "purpose": "防抖Hook" }, { "name": "useMediaQuery", "file": "hooks/use-media-query.ts", "signature": "useMediaQuery(query: string): boolean", "purpose": "响应式媒体查询Hook" }, { "name": "useLocalStorage", "file": "hooks/use-local-storage.ts", "signature": "useLocalStorage(key: string, initialValue: T): [T, (value: T | ((prev: T) => T)) => void]", "purpose": "localStorage持久化Hook" }, { "name": "usePermission", "file": "hooks/use-permission.ts", "signature": "usePermission(): { permissions: Permission[]; roles: string[]; hasPermission: (p: Permission) => boolean; hasAnyPermission: (...p: Permission[]) => boolean; hasAllPermissions: (...p: Permission[]) => boolean; hasRole: (r: string) => boolean }", "purpose": "客户端权限检查Hook", "usedBy": ["layout/app-sidebar.tsx", "exams/components", "homework/components"] }, { "name": "logDataChange", "file": "lib/change-logger.ts", "signature": "logDataChange(params: LogDataChangeParams): Promise", "purpose": "记录数据变更日志(写入 dataChangeLogs 表,自动获取 changedBy/changedByName/ipAddress;静默失败)", "deps": ["auth", "shared/db (dataChangeLogs)", "next/headers", "@paralleldrive/cuid2"], "usedBy": ["待扩展(数据变更场景)"] }, { "name": "StorageProvider", "file": "lib/storage-provider.ts", "signature": "interface StorageProvider { save(file: Buffer, storagePath: string): Promise; read(storagePath: string): Promise; delete(storagePath: string): Promise; exists(storagePath: string): Promise; getUrl(storagePath: string): string }", "purpose": "文件存储抽象接口,便于未来切换到 OSS/S3", "usedBy": ["app/api/files/batch-delete/route.ts"] }, { "name": "LocalStorageProvider", "file": "lib/storage-provider.ts", "signature": "class LocalStorageProvider implements StorageProvider", "purpose": "本地磁盘存储实现,文件持久化到 public/uploads/...,URL 为 /uploads/...", "deps": ["fs/promises", "path"], "usedBy": ["通过 storageProvider 实例使用"] }, { "name": "storageProvider", "file": "lib/storage-provider.ts", "signature": "const storageProvider: StorageProvider", "purpose": "默认存储 Provider 单例(LocalStorageProvider 实例),替换此实例可迁移到 OSS/S3", "usedBy": ["app/api/files/batch-delete/route.ts"] } ], "components": [ {"name": "AuthSessionProvider", "file": "components/auth-session-provider.tsx", "purpose": "NextAuth SessionProvider包装", "usedBy": ["app/layout.tsx"]}, {"name": "OnboardingGate", "file": "components/onboarding-gate.tsx", "purpose": "新用户引导流程", "usedBy": ["app/layout.tsx"]}, {"name": "ThemeProvider", "file": "components/theme-provider.tsx", "purpose": "next-themes主题切换", "usedBy": ["app/layout.tsx"]}, {"name": "EmptyState", "file": "components/ui/empty-state.tsx", "purpose": "列表空状态展示", "usedBy": ["exams", "homework", "questions", "textbooks"]}, {"name": "GlobalSearch", "file": "components/global-search.tsx", "props": "{ className?, placeholder? }", "purpose": "全局搜索组件(防抖300ms调用 GET /api/search,Cmd/Ctrl+K快捷键聚焦,Escape关闭,↑/↓键盘导航,Enter跳转;下拉展示 question/textbook/exam/announcement 四类结果)", "internalDeps": ["useDebounce", "Input", "Link", "useRouter"], "usedBy": ["layout/components/site-header.tsx"]}, {"name": "Switch", "file": "components/ui/switch.tsx", "basedOn": "@radix-ui/react-switch", "props": "Radix Switch Root props (checked, onCheckedChange, disabled, id, aria-label)", "purpose": "开关切换UI组件(shadcn风格,checked/unchecked两态)", "usedBy": ["settings/components/notification-preferences-form.tsx"]} ], "constants": [ {"name": "ROLE_PERMISSIONS", "file": "lib/permissions.ts", "type": "const", "description": "角色-权限映射表", "usedBy": ["resolvePermissions", "auth.ts JWT callback"]}, {"name": "Permissions", "file": "types/permissions.ts", "type": "const", "description": "38个权限点常量对象(含 FILE_UPLOAD/FILE_READ/FILE_DELETE)", "usedBy": ["auth-guard", "use-permission", "所有actions"]}, {"name": "db", "file": "db/index.ts", "type": "const", "description": "Drizzle ORM 实例", "usedBy": ["所有业务模块"]}, {"name": "questionTypeEnum", "file": "db/schema.ts", "type": "const", "description": "题目类型枚举", "usedBy": ["questions", "exams"]}, {"name": "classEnrollmentStatusEnum", "file": "db/schema.ts", "type": "const", "description": "选课状态枚举", "usedBy": ["classes"]} ], "files": [ {"path": "db/relations.ts", "description": "20+ 个 Drizzle relations 定义", "usedBy": ["所有业务模块的关联查询"]}, {"path": "next-auth.d.ts", "description": "NextAuth Session/JWT 类型扩展声明", "usedBy": ["auth.ts", "useSession"]} ], "types": [ {"name": "ActionState", "file": "types/action-state.ts", "definition": "ActionState = { success: boolean; message?: string; errors?: Record; data?: T }", "usedBy": ["所有模块Server Action"]}, {"name": "Permission", "file": "types/permissions.ts", "definition": "Permission = (typeof Permissions)[keyof typeof Permissions]", "usedBy": ["auth-guard", "use-permission", "所有actions"]}, {"name": "DataScope", "file": "types/permissions.ts", "definition": "DataScope = { type: 'all' } | { type: 'owned'; userId: string } | { type: 'class_taught'; classIds: string[]; subjectIds?: string[] } | { type: 'grade_managed'; gradeIds: string[] } | { type: 'class_members' } | { type: 'children'; childrenIds: string[] }", "usedBy": ["auth-guard", "exams/data-access", "homework/data-access", "dashboard/data-access", "grades/data-access", "parent/children/[studentId]/page.tsx"]}, {"name": "AuthContext", "file": "types/permissions.ts", "definition": "AuthContext = { userId: string; roles: string[]; permissions: Permission[]; dataScope: DataScope }", "usedBy": ["auth-guard", "所有调用requirePermission的Server Action"]}, {"name": "PermissionDeniedError", "file": "lib/auth-guard.ts", "definition": "class PermissionDeniedError extends Error { constructor(permission: string) }", "usedBy": ["所有Server Action的try/catch"]} ] }, "dbTables": { "users": {"fields": ["id","name","email","emailVerified","image","password","phone","address","gender","age","birthDate","guardianName","guardianPhone","guardianRelation","consentAcceptedAt","gradeId","departmentId","onboardedAt","createdAt","updatedAt"], "usedBy": ["auth","users","dashboard","classes"]}, "accounts": {"fields": ["userId","type","provider","providerAccountId","refresh_token","access_token","expires_at","token_type","scope","id_token","session_state"], "usedBy": ["auth"]}, "sessions": {"fields": ["sessionToken","userId","expires"], "usedBy": ["auth"]}, "verificationTokens": {"fields": ["identifier","token","expires"], "usedBy": ["auth"]}, "roles": {"fields": ["id","name","description","createdAt","updatedAt"], "usedBy": ["auth","auth-guard"]}, "usersToRoles": {"fields": ["userId","roleId"], "usedBy": ["auth","auth-guard"]}, "rolePermissions": {"fields": ["roleId","permission"], "usedBy": ["auth (seed)"]}, "knowledgePoints": {"fields": ["id","name","description","anchorText","parentId","chapterId","level","order","createdAt","updatedAt"], "usedBy": ["textbooks","questions"]}, "questions": {"fields": ["id","content","type","difficulty","authorId","parentId","createdAt","updatedAt"], "usedBy": ["questions","exams","homework"]}, "questionsToKnowledgePoints": {"fields": ["questionId","knowledgePointId"], "usedBy": ["questions"]}, "subjects": {"fields": ["id","name","code","order","createdAt","updatedAt"], "usedBy": ["exams","textbooks"]}, "textbooks": {"fields": ["id","title","subject","grade","publisher","createdAt","updatedAt"], "usedBy": ["textbooks"]}, "chapters": {"fields": ["id","textbookId","title","order","parentId","content","createdAt","updatedAt"], "usedBy": ["textbooks"]}, "departments": {"fields": ["id","name","description","createdAt","updatedAt"], "usedBy": ["school"]}, "classrooms": {"fields": ["id","name","building","floor","capacity","createdAt","updatedAt"], "usedBy": ["school"]}, "academicYears": {"fields": ["id","name","startDate","endDate","isActive","createdAt","updatedAt"], "usedBy": ["school"]}, "schools": {"fields": ["id","name","code","createdAt","updatedAt"], "usedBy": ["school","classes"]}, "grades": {"fields": ["id","schoolId","name","order","gradeHeadId","teachingHeadId","createdAt","updatedAt"], "usedBy": ["school","classes","exams","auth-guard"]}, "classes": {"fields": ["id","schoolId","gradeId","teacherId","name","homeroom","room","invitationCode","schoolName","grade","createdAt","updatedAt"], "usedBy": ["classes","homework","auth-guard"]}, "classSubjectTeachers": {"fields": ["classId","teacherId","subjectId","createdAt","updatedAt"], "usedBy": ["classes","auth-guard"]}, "classEnrollments": {"fields": ["classId","studentId","status","createdAt"], "usedBy": ["classes","homework"]}, "classSchedule": {"fields": ["id","classId","weekday","startTime","endTime","course","location","createdAt","updatedAt"], "usedBy": ["classes"]}, "exams": {"fields": ["id","creatorId","title","description","subjectId","gradeId","status","structure","startTime","endTime","createdAt","updatedAt"], "usedBy": ["exams","homework"]}, "examQuestions": {"fields": ["examId","questionId","score","order"], "usedBy": ["exams"]}, "examSubmissions": {"fields": ["id","examId","studentId","score","submittedAt","status","createdAt","updatedAt"], "usedBy": ["exams"]}, "submissionAnswers": {"fields": ["id","submissionId","questionId","answerContent","score","feedback","createdAt","updatedAt"], "usedBy": ["exams"]}, "homeworkAssignments": {"fields": ["id","creatorId","sourceExamId","title","description","status","availableAt","dueAt","allowLate","lateDueAt","maxAttempts","structure","createdAt","updatedAt"], "usedBy": ["homework"]}, "homeworkAssignmentQuestions": {"fields": ["assignmentId","questionId","score","order"], "usedBy": ["homework"]}, "homeworkAssignmentTargets": {"fields": ["assignmentId","studentId","createdAt"], "usedBy": ["homework"]}, "homeworkSubmissions": {"fields": ["id","assignmentId","studentId","status","attemptNo","score","submittedAt","startedAt","isLate","createdAt","updatedAt"], "usedBy": ["homework"]}, "homeworkAnswers": {"fields": ["id","submissionId","questionId","answerContent","score","feedback","createdAt","updatedAt"], "usedBy": ["homework"]}, "aiProviders": {"fields": ["id","provider","baseUrl","model","apiKeyEncrypted","apiKeyLast4","isDefault","createdBy","updatedBy","createdAt","updatedAt"], "usedBy": ["settings","ai"]}, "auditLogs": {"fields": ["id","userId","userName","action","module","targetId","targetType","detail","ipAddress","userAgent","status","createdAt"], "usedBy": ["audit","shared/lib/audit-logger"]}, "loginLogs": {"fields": ["id","userId","userEmail","action","status","ipAddress","userAgent","errorMessage","createdAt"], "usedBy": ["audit","shared/lib/login-logger","auth"]}, "dataChangeLogs": {"fields": ["id","tableName","recordId","action","oldValue","newValue","changedBy","changedByName","ipAddress","createdAt"], "usedBy": ["audit","shared/lib/change-logger"]}, "announcements": {"fields": ["id","title","content","type","status","targetGradeId","targetClassId","authorId","publishedAt","createdAt","updatedAt"], "usedBy": ["announcements"]}, "fileAttachments": {"fields": ["id","filename","originalName","mimeType","size","storagePath","url","uploaderId","targetType","targetId","createdAt"], "usedBy": ["files"]}, "gradeRecords": {"fields": ["id","studentId","classId","subjectId","examId","academicYearId","title","score","fullScore","type","semester","recordedBy","remark","createdAt","updatedAt"], "usedBy": ["grades"]}, "coursePlans": {"fields": ["id","classId","subjectId","teacherId","academicYearId","semester","totalHours","completedHours","weeklyHours","startDate","endDate","syllabus","objectives","status","createdBy","createdAt","updatedAt"], "usedBy": ["course-plans"]}, "coursePlanItems": {"fields": ["id","planId","week","topic","content","hours","textbookChapter","notes","isCompleted","completedAt","createdAt","updatedAt"], "usedBy": ["course-plans"]}, "parentStudentRelations": {"fields": ["id","parentId","studentId","relation","createdAt"], "usedBy": ["parent","auth-guard"]}, "messages": {"fields": ["id","senderId","receiverId","subject","content","isRead","readAt","parentMessageId","createdAt"], "usedBy": ["messaging"]}, "messageNotifications": {"fields": ["id","userId","type","title","content","link","isRead","createdAt"], "usedBy": ["messaging"]}, "notificationPreferences": {"fields": ["id","userId","emailEnabled","smsEnabled","pushEnabled","homeworkNotifications","gradeNotifications","announcementNotifications","messageNotifications","attendanceNotifications","createdAt","updatedAt"], "usedBy": ["messaging","settings"]}, "attendanceRecords": {"fields": ["id","studentId","classId","scheduleId","date","status","remark","recordedBy","createdAt","updatedAt"], "usedBy": ["attendance"]}, "attendanceRules": {"fields": ["id","classId","lateThresholdMinutes","earlyLeaveThresholdMinutes","enableAutoMark","createdAt","updatedAt"], "usedBy": ["attendance"]}, "schedulingRules": {"fields": ["id","classId","maxDailyHours","maxContinuousHours","lunchBreakStart","lunchBreakEnd","morningStart","afternoonEnd","avoidBackToBack","balancedSubjects","createdAt","updatedAt"], "usedBy": ["scheduling"]}, "scheduleChanges": {"fields": ["id","originalScheduleId","classId","originalTeacherId","substituteTeacherId","originalDate","newDate","newStartTime","newEndTime","reason","status","requestedBy","approvedBy","createdAt","updatedAt"], "usedBy": ["scheduling"]}, "passwordSecurity": {"fields": ["id","userId","failedLoginAttempts","lockedUntil","passwordChangedAt","mustChangePassword","lastPasswordChange","createdAt","updatedAt"], "usedBy": ["auth","settings"]}, "knowledgePointMastery": {"fields": ["id","studentId","knowledgePointId","masteryLevel","totalQuestions","correctQuestions","lastAssessedAt","createdAt","updatedAt"], "usedBy": ["diagnostic"], "description": "知识点掌握度记录(复合主键 studentId+knowledgePointId,onDuplicateKeyUpdate upsert)"}, "learningDiagnosticReports": {"fields": ["id","studentId","generatedBy","reportType","period","summary","strengths","weaknesses","recommendations","overallScore","status","createdAt","updatedAt"], "usedBy": ["diagnostic"], "description": "学情诊断报告(reportType: individual/class/grade;status: draft/published/archived)"}, "electiveCourses": {"fields": ["id","name","subjectId","teacherId","gradeId","description","capacity","enrolledCount","classroom","schedule","startDate","endDate","selectionStartAt","selectionEndAt","status","selectionMode","credit","createdAt","updatedAt"], "usedBy": ["elective"], "description": "选修课程(status: draft/open/closed/cancelled;selectionMode: fcfs/lottery)"}, "courseSelections": {"fields": ["id","courseId","studentId","status","priority","selectedAt","enrolledAt","droppedAt","lotteryRank","createdAt","updatedAt"], "usedBy": ["elective"], "description": "选课记录(复合主键 courseId+studentId;status: selected/enrolled/waitlist/dropped/rejected)"} } }, "auth": { "path": "src/auth.ts", "description": "用户认证:NextAuth配置、JWT/Session callbacks、events回调(登录日志)、middleware。集成密码安全策略(账户锁定、失败登录追踪)和登录速率限制", "exports": { "functions": [ {"name": "auth", "signature": "auth(): Promise", "purpose": "获取当前用户Session", "usedBy": ["auth-guard.ts", "所有Server Component页面", "audit-logger.ts"]}, {"name": "handlers", "signature": "{ GET, POST }", "purpose": "NextAuth Route Handler", "usedBy": ["app/api/auth/[...nextauth]/route.ts"]}, {"name": "signIn", "signature": "signIn(provider, options?)", "purpose": "登录", "usedBy": ["login-form.tsx"]}, {"name": "signOut", "signature": "signOut(options?)", "purpose": "登出", "usedBy": ["site-header.tsx"]} ], "events": [ {"name": "signIn", "signature": "async signIn({ user }) => void", "purpose": "用户登录成功后记录登录日志", "deps": ["shared/lib/login-logger.logLoginEvent"], "params": "{ userId: user.id, userEmail: user.email, action: 'signin', status: 'success' }"}, {"name": "signOut", "signature": "async signOut(message) => void", "purpose": "用户登出后记录登录日志(处理NextAuth v5不同message形状)", "deps": ["shared/lib/login-logger.logLoginEvent"], "params": "{ userId?, userEmail, action: 'signout', status: 'success' }"} ] }, "middleware": { "file": "src/proxy.ts", "signature": "middleware(request: NextRequest): Promise", "purpose": "基于权限点的路由守卫", "routePermissions": { "/admin": "school:manage", "/teacher": "exam:read", "/student": "homework:submit", "/parent": "exam:read", "/management": "grade:manage" }, "apiPermissions": { "/api/ai/chat": "ai:chat" } } }, "exams": { "path": "src/modules/exams", "description": "考试全生命周期:创建(手动/AI)、编辑、预览、发布、删除、复制", "exports": { "actions": [ {"name": "createExamAction", "permission": "EXAM_CREATE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "手动模式创建考试草稿", "deps": ["requirePermission","shared/db","data-access.persistExamDraft"], "usedBy": ["exam-form.tsx"]}, {"name": "createAiExamAction", "permission": "EXAM_AI_GENERATE", "signature": "同上", "purpose": "AI模式创建考试", "deps": ["requirePermission","ai-pipeline.generateAiCreateDraftFromSource","data-access.persistAiGeneratedExamDraft"], "usedBy": ["exam-form.tsx"]}, {"name": "previewAiExamAction", "permission": "EXAM_AI_GENERATE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "AI预览试卷(不持久化)", "deps": ["requirePermission","ai-pipeline.generateAiPreviewData"], "usedBy": ["exam-ai-generator.tsx"]}, {"name": "regenerateAiQuestionAction", "permission": "EXAM_AI_GENERATE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "AI重写单个题目", "deps": ["requirePermission","ai-pipeline.regenerateAiQuestionByInstruction"], "usedBy": ["exam-preview-question-editor.tsx"]}, {"name": "updateExamAction", "permission": "EXAM_UPDATE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "更新考试(含资源归属校验)", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-form.tsx"]}, {"name": "deleteExamAction", "permission": "EXAM_DELETE", "signature": "同上", "purpose": "删除考试(含资源归属校验)", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-actions.tsx"]}, {"name": "duplicateExamAction", "permission": "EXAM_DUPLICATE", "signature": "同上", "purpose": "复制考试", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-actions.tsx"]}, {"name": "getExamPreviewAction", "permission": "EXAM_READ", "signature": "(examId: string) => Promise }>>", "purpose": "获取考试预览数据", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-viewer.tsx"]}, {"name": "getSubjectsAction", "permission": "EXAM_READ", "signature": "() => Promise>", "purpose": "获取科目列表", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-form.tsx"]}, {"name": "getGradesAction", "permission": "EXAM_READ", "signature": "同上", "purpose": "获取年级列表", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-form.tsx"]} ], "dataAccess": [ {"name": "getExams", "signature": "getExams(params: GetExamsParams & { scope: DataScope }): Promise", "purpose": "查询考试列表(含数据权限过滤)", "usedBy": ["teacher/exams/all/page.tsx", "homework创建页面"]}, {"name": "getExamById", "signature": "getExamById(id: string, scope?: DataScope): Promise", "purpose": "按ID获取考试详情", "usedBy": ["exam详情/编辑页面"]}, {"name": "persistExamDraft", "signature": "persistExamDraft(input: { examId, title, creatorId, subjectId, gradeId, scheduledAt?, description }): Promise", "purpose": "持久化手动考试草稿", "usedBy": ["createExamAction"]}, {"name": "persistAiGeneratedExamDraft", "signature": "persistAiGeneratedExamDraft(input: { examId, title, creatorId, subjectId, gradeId, scheduledAt?, description, structure, generated }): Promise", "purpose": "持久化AI生成考试草稿", "usedBy": ["createAiExamAction"]}, {"name": "omitScheduledAtFromDescription", "signature": "(description: string | null) => string", "purpose": "从描述中移除scheduledAt信息", "usedBy": ["exams/data-access内部"]}, {"name": "resolveSubjectGradeNames", "signature": "(input: { subjectId?, gradeId? }) => Promise<{ subjectName?, gradeName? }>", "purpose": "解析科目与年级名称", "usedBy": ["exams/data-access内部"]}, {"name": "buildExamDescription", "signature": "(input: { subject, grade, difficulty, totalScore, durationMin, scheduledAt?, questionCount? }) => string", "purpose": "构建考试描述文本", "usedBy": ["exams/data-access内部"]}, {"name": "GetExamsParams", "type": "type", "definition": "{ q?, status?, difficulty?, page?, pageSize? }", "usedBy": ["getExams", "getExamsAction"]} ], "aiPipeline": [ {"name": "generateAiPreviewData", "signature": "(input: { title, subject?, grade?, difficulty, totalScore, durationMin, questionCount?, sourceText, aiProviderId? }) => Promise<{ ok, data?, rawOutput?, message? }>", "purpose": "AI预览生成", "deps": ["shared/lib/ai.createAiChatCompletion"], "usedBy": ["previewAiExamAction"]}, {"name": "generateAiCreateDraftFromSource", "signature": "同上", "purpose": "AI从源文本生成完整考试", "deps": ["shared/lib/ai.createAiChatCompletion"], "usedBy": ["createAiExamAction"]}, {"name": "regenerateAiQuestionByInstruction", "signature": "(input: { instruction, originalQuestion, sourceText?, aiProviderId? }) => Promise<{ ok, data?, message? }>", "purpose": "AI按指令重写题目", "deps": ["shared/lib/ai.createAiChatCompletion"], "usedBy": ["regenerateAiQuestionAction"]}, {"name": "AiQuestionSchema", "type": "const", "description": "zod schema 校验AI生成题目", "usedBy": ["ai-pipeline内部"]}, {"name": "AiInsertQuestionSchema", "type": "const", "description": "zod schema 校验AI插入题目", "usedBy": ["ai-pipeline内部"]}, {"name": "AiGeneratedQuestion", "type": "type", "definition": "{ id, type, difficulty, score, content }", "usedBy": ["ai-pipeline内部", "exams/components"]}, {"name": "AiGeneratedStructureNode", "type": "type", "definition": "{ id, type: \"group\"|\"question\", title?, questionId?, score?, children? }", "usedBy": ["ai-pipeline内部", "exams/components"]}, {"name": "AiGeneratedStructureNodeSchema", "type": "const", "description": "zod schema 校验AI生成结构节点(递归)", "usedBy": ["ai-pipeline内部"]}, {"name": "AiGeneratedStructureSchema", "type": "const", "description": "zod schema 校验AI生成结构", "usedBy": ["ai-pipeline内部"]}, {"name": "generateAiExamDraft", "type": "function", "signature": "(input) => Promise", "purpose": "生成AI考试草稿", "deps": ["shared/lib/ai.createAiChatCompletion"], "usedBy": ["ai-pipeline内部"]} ], "types": [ {"name": "Exam", "definition": "{ id, title, subject, grade, status, difficulty, totalScore, durationMin, questionCount, scheduledAt?, createdAt, updatedAt?, tags? }", "usedBy": ["exams/components", "homework/types", "dashboard/types"]}, {"name": "AiPreviewData", "definition": "{ title, rawOutput?, sections?, questions? }", "usedBy": ["exams/actions", "exams/components"]}, {"name": "AiRewriteQuestionData", "definition": "{ type, difficulty, score, content }", "usedBy": ["exams/actions", "exams/components"]}, {"name": "ExamStatus", "type": "type", "definition": "\"draft\" | \"published\" | \"archived\"", "usedBy": ["exams/components", "exams/data-access"]}, {"name": "ExamDifficulty", "type": "type", "definition": "1 | 2 | 3 | 4 | 5", "usedBy": ["exams/components", "exams/data-access"]}, {"name": "SubmissionStatus", "type": "type", "definition": "\"pending\" | \"graded\"", "usedBy": ["exams/components", "exams/data-access"]}, {"name": "ExamSubmission", "type": "interface", "definition": "{ id, examId, examTitle, studentName, submittedAt, score?, status }", "usedBy": ["exams/components"]} ], "components": [ {"name": "ExamPaperPreview", "file": "assembly/exam-paper-preview.tsx", "purpose": "试卷预览"}, {"name": "QuestionBankList", "file": "assembly/question-bank-list.tsx", "purpose": "题库列表(组卷选择)"}, {"name": "SelectedQuestionList", "file": "assembly/selected-question-list.tsx", "purpose": "已选题目列表", "types": ["ExamNode"]}, {"name": "StructureEditor", "file": "assembly/structure-editor.tsx", "purpose": "试卷结构编辑器"}, {"name": "ExamActions", "file": "exam-actions.tsx", "purpose": "考试操作按钮(删除/复制等)"}, {"name": "ExamAiGenerator", "file": "exam-ai-generator.tsx", "purpose": "AI生成考试面板"}, {"name": "ExamAssembly", "file": "exam-assembly.tsx", "purpose": "组卷主界面"}, {"name": "ExamBasicInfoForm", "file": "exam-basic-info-form.tsx", "purpose": "考试基本信息表单"}, {"name": "ExamCard", "file": "exam-card.tsx", "purpose": "考试卡片"}, {"name": "examColumns", "file": "exam-columns.tsx", "type": "ColumnDef[]", "purpose": "考试表格列定义"}, {"name": "ExamDataTable", "file": "exam-data-table.tsx", "purpose": "考试数据表格"}, {"name": "ExamFilters", "file": "exam-filters.tsx", "purpose": "考试筛选器"}, {"name": "formSchema", "file": "exam-form-types.ts", "type": "const", "purpose": "表单zod schema"}, {"name": "ExamFormValues", "file": "exam-form-types.ts", "type": "type", "purpose": "表单值类型"}, {"name": "PreviewQuestion", "file": "exam-form-types.ts", "type": "type", "purpose": "预览题目类型"}, {"name": "EditableQuestionContent", "file": "exam-form-types.ts", "type": "type", "purpose": "可编辑题目内容"}, {"name": "PreviewSnapshotMeta", "file": "exam-form-types.ts", "type": "type", "purpose": "预览快照元数据"}, {"name": "PreviewBackgroundTask", "file": "exam-form-types.ts", "type": "type", "purpose": "预览后台任务"}, {"name": "aiProviderLabels", "file": "exam-form-types.ts", "type": "const", "purpose": "AI Provider标签映射"}, {"name": "defaultValues", "file": "exam-form-types.ts", "type": "const", "purpose": "表单默认值"}, {"name": "previewTaskStorageKey", "file": "exam-form-types.ts", "type": "const", "purpose": "预览任务localStorage key"}, {"name": "ExamForm", "file": "exam-form.tsx", "purpose": "考试表单(创建/编辑)"}, {"name": "ExamGrid", "file": "exam-grid.tsx", "purpose": "考试网格视图"}, {"name": "ExamModeSelector", "file": "exam-mode-selector.tsx", "purpose": "考试模式选择(手动/AI)"}, {"name": "ExamPreviewDialog", "file": "exam-preview-dialog.tsx", "purpose": "考试预览对话框"}, {"name": "ExamPreviewQuestionEditor", "file": "exam-preview-question-editor.tsx", "purpose": "预览题目编辑器"}, {"name": "buildPreviewNodes", "file": "exam-preview-utils.ts", "type": "function", "purpose": "构建预览节点"}, {"name": "parseEditableContent", "file": "exam-preview-utils.ts", "type": "function", "purpose": "解析可编辑内容"}, {"name": "flattenPreviewQuestions", "file": "exam-preview-utils.ts", "type": "function", "purpose": "扁平化预览题目"}, {"name": "findPreviewQuestionNode", "file": "exam-preview-utils.ts", "type": "function", "purpose": "查找预览题目节点"}, {"name": "updatePreviewQuestionNodeInList", "file": "exam-preview-utils.ts", "type": "function", "purpose": "更新预览题目节点"}, {"name": "buildPreviewSignature", "file": "exam-preview-utils.ts", "type": "function", "purpose": "构建预览签名"}, {"name": "buildPreviewPayload", "file": "exam-preview-utils.ts", "type": "function", "purpose": "构建预览payload"}, {"name": "buildPreviewRequestData", "file": "exam-preview-utils.ts", "type": "function", "purpose": "构建预览请求数据"}, {"name": "ExamViewer", "file": "exam-viewer.tsx", "purpose": "考试查看器"}, {"name": "QuestionOptionsEditor", "file": "question-options-editor.tsx", "purpose": "题目选项编辑器"}, {"name": "QuestionSubQuestionsEditor", "file": "question-sub-questions-editor.tsx", "purpose": "子题目编辑器"} ], "hooks": [ {"name": "useExamPreview", "file": "use-exam-preview.ts", "signature": "(form: UseFormReturn) => { previewOpen, setPreviewOpen, previewLoading, previewNodes, handlePreview, handleBackgroundPreview, handleOpenPreviewTask, handleRewriteSelectedQuestion }", "purpose": "考试预览Hook", "usedBy": ["exam-form.tsx"]} ] } }, "homework": { "path": "src/modules/homework", "description": "作业全生命周期:创建(源自考试)、发布、学生作答、教师批改、数据分析", "exports": { "actions": [ {"name": "createHomeworkAssignmentAction", "permission": "HOMEWORK_CREATE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "从已有考试创建作业", "deps": ["requirePermission","shared/db","exams/data-access.getExams"], "usedBy": ["homework-assignment-form.tsx"]}, {"name": "startHomeworkSubmissionAction", "permission": "HOMEWORK_SUBMIT", "signature": "同上", "purpose": "学生开始作答", "deps": ["requirePermission","shared/db"], "usedBy": ["homework-take-view.tsx"]}, {"name": "saveHomeworkAnswerAction", "permission": "HOMEWORK_SUBMIT", "signature": "同上", "purpose": "保存单题答案", "deps": ["requirePermission","shared/db"], "usedBy": ["homework-take-view.tsx"]}, {"name": "submitHomeworkAction", "permission": "HOMEWORK_SUBMIT", "signature": "同上", "purpose": "提交作业", "deps": ["requirePermission","shared/db"], "usedBy": ["homework-take-view.tsx"]}, {"name": "gradeHomeworkSubmissionAction", "permission": "HOMEWORK_GRADE", "signature": "同上", "purpose": "教师批改作业", "deps": ["requirePermission","shared/db"], "usedBy": ["homework-grading-view.tsx"]} ], "dataAccess": [ {"name": "getTeacherGradeTrends", "signature": "(teacherId: string, limit?: number) => Promise", "usedBy": ["dashboard (教师仪表盘)"]}, {"name": "getHomeworkAssignments", "signature": "(params?: { creatorId?, ids?, classId?, scope? }) => Promise", "usedBy": ["teacher作业列表页", "homework-assignment-form.tsx"]}, {"name": "getHomeworkAssignmentReviewList", "signature": "(params: { creatorId: string; scope? }) => Promise", "usedBy": ["teacher批改列表"]}, {"name": "getHomeworkSubmissions", "signature": "(params?: { assignmentId?, classId?, creatorId?, scope? }) => Promise", "usedBy": ["teacher提交列表"]}, {"name": "getStudentHomeworkAssignments", "signature": "(studentId: string) => Promise", "usedBy": ["student/dashboard"]}, {"name": "getStudentDashboardGrades", "signature": "(studentId: string) => Promise", "usedBy": ["dashboard/data-access.ts"]}, {"name": "getHomeworkAssignmentAnalytics", "signature": "(assignmentId: string) => Promise", "usedBy": ["homework错误分析组件"]}, {"name": "getHomeworkAssignmentById", "signature": "(id: string, scope?: DataScope) => Promise<...>", "purpose": "按ID获取作业详情", "usedBy": ["homework详情页"]}, {"name": "getHomeworkSubmissionDetails", "signature": "(submissionId: string) => Promise", "purpose": "获取提交详情(含答案)", "usedBy": ["homework-grading-view.tsx"]}, {"name": "getDemoStudentUser", "signature": "() => Promise<{ id: string; name: string } | null>", "purpose": "获取演示学生用户", "usedBy": ["homework内部"]}, {"name": "getStudentHomeworkTakeData", "signature": "(assignmentId: string, studentId: string) => Promise", "purpose": "获取学生作答数据", "usedBy": ["homework-take-view.tsx"]} ], "schema": [ {"name": "CreateHomeworkAssignmentSchema", "type": "const", "description": "zod schema 创建作业", "usedBy": ["createHomeworkAssignmentAction", "homework-assignment-form.tsx"]}, {"name": "CreateHomeworkAssignmentInput", "type": "type", "definition": "z.infer", "usedBy": ["createHomeworkAssignmentAction"]}, {"name": "GradeHomeworkSchema", "type": "const", "description": "zod schema 批改作业", "usedBy": ["gradeHomeworkSubmissionAction", "homework-grading-view.tsx"]} ], "types": [ {"name": "StudentDashboardGradeProps", "definition": "{ trend, recent, ranking }", "usedBy": ["dashboard/types.ts"]}, {"name": "HomeworkAssignmentListItem", "usedBy": ["homework列表页"]}, {"name": "StudentHomeworkTakeData", "usedBy": ["homework-take-view.tsx"]}, {"name": "HomeworkAssignmentStatus", "type": "type", "definition": "作业状态枚举", "usedBy": ["homework/components", "homework/data-access"]}, {"name": "HomeworkSubmissionStatus", "type": "type", "definition": "提交状态枚举", "usedBy": ["homework/components", "homework/data-access"]}, {"name": "TeacherGradeTrendItem", "type": "type", "definition": "教师年级趋势项", "usedBy": ["dashboard (教师仪表盘)"]}, {"name": "HomeworkAssignmentReviewListItem", "type": "type", "definition": "批改列表项", "usedBy": ["teacher批改列表"]}, {"name": "HomeworkSubmissionListItem", "type": "type", "definition": "提交列表项", "usedBy": ["teacher提交列表"]}, {"name": "HomeworkQuestionContent", "type": "type", "definition": "作业题目内容", "usedBy": ["homework/components"]}, {"name": "HomeworkSubmissionAnswerDetails", "type": "type", "definition": "提交答案详情", "usedBy": ["homework-grading-view.tsx"]}, {"name": "HomeworkSubmissionDetails", "type": "type", "definition": "提交详情(含答案列表)", "usedBy": ["homework-grading-view.tsx"]}, {"name": "StudentHomeworkProgressStatus", "type": "type", "definition": "学生作业进度状态", "usedBy": ["student/dashboard"]}, {"name": "StudentHomeworkAssignmentListItem", "type": "type", "definition": "学生作业列表项", "usedBy": ["student/dashboard"]}, {"name": "StudentHomeworkPerformanceItem", "type": "type", "definition": "学生表现项", "usedBy": ["student/dashboard"]}, {"name": "StudentHomeworkPerformanceSummary", "type": "type", "definition": "学生表现汇总", "usedBy": ["student/dashboard"]}, {"name": "StudentHomeworkTakeQuestion", "type": "type", "definition": "学生作答题目", "usedBy": ["homework-take-view.tsx"]}, {"name": "HomeworkAssignmentQuestionAnalytics", "type": "type", "definition": "作业题目分析", "usedBy": ["homework错误分析组件"]}, {"name": "HomeworkAssignmentAnalytics", "type": "type", "definition": "作业整体分析", "usedBy": ["homework错误分析组件"]}, {"name": "StudentHomeworkScoreAnalytics", "type": "type", "definition": "学生成绩分析", "usedBy": ["student/dashboard"]}, {"name": "StudentRanking", "type": "type", "definition": "学生排名", "usedBy": ["student/dashboard"]} ], "components": [ {"name": "HomeworkAssignmentExamContentCard", "file": "homework-assignment-exam-content-card.tsx", "purpose": "作业考试内容卡片"}, {"name": "HomeworkAssignmentExamErrorExplorerLazy", "file": "homework-assignment-exam-error-explorer-lazy.tsx", "purpose": "作业错误分析(懒加载)"}, {"name": "HomeworkAssignmentExamErrorExplorer", "file": "homework-assignment-exam-error-explorer.tsx", "purpose": "作业错误分析探索器"}, {"name": "HomeworkAssignmentExamPreviewPane", "file": "homework-assignment-exam-preview-pane.tsx", "purpose": "作业考试预览面板"}, {"name": "HomeworkAssignmentForm", "file": "homework-assignment-form.tsx", "purpose": "作业创建表单"}, {"name": "HomeworkAssignmentQuestionErrorDetailPanel", "file": "homework-assignment-question-error-detail-panel.tsx", "purpose": "题目错误详情面板"}, {"name": "HomeworkAssignmentQuestionErrorOverviewCard", "file": "homework-assignment-question-error-overview-card.tsx", "purpose": "题目错误概览卡片"}, {"name": "HomeworkGradingView", "file": "homework-grading-view.tsx", "purpose": "作业批改视图"}, {"name": "HomeworkTakeView", "file": "homework-take-view.tsx", "purpose": "学生作答视图"}, {"name": "HomeworkReviewView", "file": "student-homework-review-view.tsx", "purpose": "学生作业复习视图"} ] } }, "questions": { "path": "src/modules/questions", "description": "题库管理:题目CRUD、知识点关联、多题型支持", "exports": { "actions": [ {"name": "createNestedQuestion", "permission": "QUESTION_CREATE", "signature": "(prevState: ActionState | undefined, formData: FormData | CreateQuestionInput) => Promise>", "purpose": "创建题目(含嵌套)", "deps": ["requirePermission","shared/db"], "usedBy": ["create-question-dialog.tsx"]}, {"name": "updateQuestionAction", "permission": "QUESTION_UPDATE", "signature": "同上", "purpose": "更新题目", "deps": ["requirePermission","shared/db"], "usedBy": ["question-actions.tsx"]}, {"name": "deleteQuestionAction", "permission": "QUESTION_DELETE", "signature": "同上", "purpose": "删除题目", "deps": ["requirePermission","shared/db"], "usedBy": ["question-actions.tsx"]}, {"name": "getQuestionsAction", "permission": "QUESTION_READ", "signature": "(params: GetQuestionsParams) => Promise<...>", "purpose": "查询题目列表", "deps": ["requirePermission","data-access.getQuestions"], "usedBy": ["teacher/questions/page.tsx"]}, {"name": "getKnowledgePointOptionsAction", "permission": "QUESTION_READ", "signature": "() => Promise", "purpose": "获取知识点选项", "deps": ["requirePermission","shared/db"], "usedBy": ["create-question-dialog.tsx"]} ], "dataAccess": [ {"name": "getQuestions", "signature": "(params?: GetQuestionsParams) => Promise<{ data: Question[], meta: { page, pageSize, total, totalPages } }>", "type": "cache function", "purpose": "查询题目列表(缓存)", "usedBy": ["getQuestionsAction", "teacher/questions/page.tsx"]}, {"name": "GetQuestionsParams", "type": "type", "definition": "{ q?, page?, pageSize?, ids?, knowledgePointId?, type?, difficulty? }", "usedBy": ["getQuestions", "getQuestionsAction"]} ], "schema": [ {"name": "QuestionTypeEnum", "type": "const", "description": "zod enum: z.enum([\"single_choice\", \"multiple_choice\", \"text\", \"judgment\", \"composite\"])", "usedBy": ["CreateQuestionSchema", "questions/components"]}, {"name": "BaseQuestionSchema", "type": "const", "description": "zod schema 基础题目校验", "usedBy": ["CreateQuestionSchema"]}, {"name": "CreateQuestionInput", "type": "type", "definition": "z.infer", "usedBy": ["createNestedQuestion", "create-question-dialog.tsx"]}, {"name": "CreateQuestionSchema", "type": "const", "description": "zod schema 创建题目(递归支持嵌套)", "usedBy": ["createNestedQuestion", "create-question-dialog.tsx"]} ], "types": [ {"name": "Question", "definition": "{ id, content, type, difficulty, createdAt, updatedAt, author, knowledgePoints, childrenCount? }", "usedBy": ["exams (题目选择)", "homework (作业题目)"]}, {"name": "KnowledgePointOption", "definition": "{ id, name, chapterId, chapterTitle, textbookId, textbookTitle, subject, grade }", "usedBy": ["create-question-dialog.tsx"]}, {"name": "QuestionType", "type": "type", "definition": "z.infer", "usedBy": ["questions/components", "exams/components"]} ], "components": [ {"name": "CreateQuestionButton", "file": "create-question-button.tsx", "purpose": "创建题目按钮"}, {"name": "CreateQuestionDialog", "file": "create-question-dialog.tsx", "purpose": "创建题目对话框"}, {"name": "QuestionActions", "file": "question-actions.tsx", "purpose": "题目操作按钮"}, {"name": "columns", "file": "question-columns.tsx", "type": "ColumnDef[]", "purpose": "题目表格列定义"}, {"name": "QuestionDataTable", "file": "question-data-table.tsx", "purpose": "题目数据表格"}, {"name": "QuestionFilters", "file": "question-filters.tsx", "purpose": "题目筛选器"} ] } }, "textbooks": { "path": "src/modules/textbooks", "description": "教材与知识体系:教材/章节树形结构、知识点CRUD、Markdown内容编辑、知识图谱", "exports": { "actions": [ {"name": "createTextbookAction", "permission": "TEXTBOOK_CREATE", "signature": "(prevState, formData) => Promise", "purpose": "创建教材"}, {"name": "updateTextbookAction", "permission": "TEXTBOOK_UPDATE", "signature": "(textbookId, prevState, formData) => Promise", "purpose": "更新教材元信息"}, {"name": "deleteTextbookAction", "permission": "TEXTBOOK_DELETE", "signature": "(textbookId) => Promise", "purpose": "删除教材"}, {"name": "createChapterAction", "permission": "TEXTBOOK_CREATE", "signature": "(textbookId, parentId?, prevState, formData) => Promise", "purpose": "创建章节"}, {"name": "updateChapterContentAction", "permission": "TEXTBOOK_UPDATE", "signature": "(chapterId, content, textbookId) => Promise", "purpose": "更新章节内容(Markdown)"}, {"name": "deleteChapterAction", "permission": "TEXTBOOK_DELETE", "signature": "(chapterId, textbookId) => Promise", "purpose": "删除章节"}, {"name": "createKnowledgePointAction", "permission": "TEXTBOOK_CREATE", "signature": "(chapterId, textbookId, prevState, formData) => Promise", "purpose": "创建知识点"}, {"name": "updateKnowledgePointAction", "permission": "TEXTBOOK_UPDATE", "signature": "(kpId, textbookId, prevState, formData) => Promise", "purpose": "更新知识点"}, {"name": "deleteKnowledgePointAction", "permission": "TEXTBOOK_DELETE", "signature": "(kpId, textbookId) => Promise", "purpose": "删除知识点"}, {"name": "reorderChaptersAction", "permission": "TEXTBOOK_UPDATE", "signature": "(chapterId, newIndex, parentId, textbookId) => Promise", "purpose": "章节排序"} ], "dataAccess": [ {"name": "getTextbooks", "signature": "(query?, subject?, grade?) => Promise", "usedBy": ["teacher/textbooks/page.tsx"]}, {"name": "getTextbookById", "signature": "(id) => Promise", "usedBy": ["teacher/textbooks/[id]/page.tsx"]}, {"name": "getChaptersByTextbookId", "signature": "(textbookId) => Promise", "usedBy": ["textbook-reader.tsx"]}, {"name": "getKnowledgePointsByChapterId", "signature": "(chapterId) => Promise", "usedBy": ["textbook-reader.tsx"]}, {"name": "getKnowledgePointsByTextbookId", "signature": "(textbookId) => Promise", "usedBy": ["textbook-reader.tsx"]}, {"name": "createTextbook", "signature": "(input: CreateTextbookInput) => Promise", "purpose": "创建教材", "usedBy": ["createTextbookAction"]}, {"name": "updateTextbook", "signature": "(id: string, input: UpdateTextbookInput) => Promise", "purpose": "更新教材", "usedBy": ["updateTextbookAction"]}, {"name": "deleteTextbook", "signature": "(id: string) => Promise", "purpose": "删除教材", "usedBy": ["deleteTextbookAction"]}, {"name": "createChapter", "signature": "(input: CreateChapterInput) => Promise", "purpose": "创建章节", "usedBy": ["createChapterAction"]}, {"name": "updateChapterContent", "signature": "(input: UpdateChapterContentInput) => Promise", "purpose": "更新章节内容", "usedBy": ["updateChapterContentAction"]}, {"name": "deleteChapter", "signature": "(chapterId: string, textbookId: string) => Promise", "purpose": "删除章节", "usedBy": ["deleteChapterAction"]}, {"name": "createKnowledgePoint", "signature": "(input: CreateKnowledgePointInput) => Promise", "purpose": "创建知识点", "usedBy": ["createKnowledgePointAction"]}, {"name": "updateKnowledgePoint", "signature": "(input: UpdateKnowledgePointInput) => Promise", "purpose": "更新知识点", "usedBy": ["updateKnowledgePointAction"]}, {"name": "deleteKnowledgePoint", "signature": "(kpId: string, textbookId: string) => Promise", "purpose": "删除知识点", "usedBy": ["deleteKnowledgePointAction"]}, {"name": "reorderChapters", "signature": "(chapterId: string, newIndex: number, parentId: string | null, textbookId: string) => Promise", "purpose": "章节排序", "usedBy": ["reorderChaptersAction"]} ], "hooks": [ {"name": "useTextSelection", "file": "hooks/use-text-selection.ts", "signature": "() => { selectedText, setSelectedText, selectionRef, contentRef, setCreateDialogOpen, setIsCreating, createDialogOpen, isCreating, handleContentPointerDown, handleContextMenuChange }", "purpose": "文本选区Hook(无参数)", "usedBy": ["textbook-content-panel.tsx"]}, {"name": "useKnowledgePointActions", "file": "hooks/use-knowledge-point-actions.ts", "signature": "(textbookId, selectedChapterId, selectedChapterTextbookId, highlightedKpId, setHighlightedKpId, onKpCreated?) => { editingKp, setEditingKp, editKpDialogOpen, setEditKpDialogOpen, isUpdatingKp, questionDialogOpen, setQuestionDialogOpen, targetKpForQuestion, setTargetKpForQuestion, deleteConfirmOpen, setDeleteConfirmOpen, handleCreateKnowledgePoint, requestDeleteKP, confirmDeleteKP, handleUpdateKP }", "purpose": "知识点操作Hook(6参数)", "usedBy": ["textbook-reader.tsx"]} ], "types": [ {"name": "Chapter", "definition": "{ id, textbookId, title, order, parentId, content?, children? }", "usedBy": ["textbooks/components", "questions (知识点关联)"]}, {"name": "KnowledgePoint", "definition": "{ id, name, description?, anchorText?, parentId?, chapterId?, level, order }", "usedBy": ["textbooks/components", "questions/types"]}, {"name": "Textbook", "type": "type", "definition": "{ id, title, subject, grade, publisher, createdAt, updatedAt }", "usedBy": ["textbooks/components", "textbooks/data-access"]}, {"name": "CreateTextbookInput", "type": "type", "definition": "创建教材输入", "usedBy": ["createTextbook", "createTextbookAction"]}, {"name": "UpdateTextbookInput", "type": "type", "definition": "更新教材输入", "usedBy": ["updateTextbook", "updateTextbookAction"]}, {"name": "CreateChapterInput", "type": "type", "definition": "创建章节输入", "usedBy": ["createChapter", "createChapterAction"]}, {"name": "UpdateChapterContentInput", "type": "type", "definition": "更新章节内容输入", "usedBy": ["updateChapterContent", "updateChapterContentAction"]}, {"name": "CreateKnowledgePointInput", "type": "type", "definition": "创建知识点输入", "usedBy": ["createKnowledgePoint", "createKnowledgePointAction"]}, {"name": "UpdateKnowledgePointInput", "type": "type", "definition": "更新知识点输入", "usedBy": ["updateKnowledgePoint", "updateKnowledgePointAction"]} ], "components": [ {"name": "ChapterSidebarList", "purpose": "章节侧边栏列表"}, {"name": "CreateChapterDialog", "purpose": "创建章节对话框"}, {"name": "CreateKnowledgePointDialog", "purpose": "创建知识点对话框"}, {"name": "KnowledgeGraph", "purpose": "知识图谱可视化"}, {"name": "KnowledgePointDialogs", "purpose": "知识点对话框集合"}, {"name": "KnowledgePointList", "purpose": "知识点列表"}, {"name": "KnowledgePointPanel", "purpose": "知识点面板"}, {"name": "TextbookCard", "purpose": "教材卡片"}, {"name": "TextbookContentPanel", "purpose": "教材内容面板"}, {"name": "TextbookFilters", "purpose": "教材筛选器"}, {"name": "TextbookFormDialog", "purpose": "教材表单对话框"}, {"name": "TextbookReader", "purpose": "教材阅读器"}, {"name": "TextbookSettingsDialog", "purpose": "教材设置对话框"} ] } }, "classes": { "path": "src/modules/classes", "description": "班级管理:班级CRUD、学生注册/退班、邀请码、课表、学科教师分配", "exports": { "actions": [ {"name": "createTeacherClassAction", "permission": "CLASS_CREATE", "signature": "(prevState, formData) => Promise>", "purpose": "教师创建班级"}, {"name": "updateTeacherClassAction", "permission": "CLASS_UPDATE", "signature": "(classId, prevState, formData) => Promise", "purpose": "教师更新班级"}, {"name": "deleteTeacherClassAction", "permission": "CLASS_DELETE", "signature": "(classId) => Promise", "purpose": "教师删除班级"}, {"name": "createGradeClassAction", "permission": "CLASS_CREATE", "signature": "(prevState, formData) => Promise>", "purpose": "年级主任创建班级"}, {"name": "updateGradeClassAction", "permission": "CLASS_UPDATE", "signature": "(classId, prevState, formData) => Promise", "purpose": "年级主任更新班级"}, {"name": "deleteGradeClassAction", "permission": "CLASS_DELETE", "signature": "(classId) => Promise", "purpose": "年级主任删除班级"}, {"name": "enrollStudentByEmailAction", "permission": "CLASS_ENROLL", "signature": "(classId, prevState, formData) => Promise", "purpose": "通过邮箱注册学生"}, {"name": "joinClassByInvitationCodeAction", "permission": "CLASS_ENROLL", "signature": "(prevState, formData) => Promise>", "purpose": "通过邀请码加入"}, {"name": "ensureClassInvitationCodeAction", "permission": "CLASS_ENROLL", "signature": "(classId) => Promise>", "purpose": "确保邀请码存在"}, {"name": "regenerateClassInvitationCodeAction", "permission": "CLASS_ENROLL", "signature": "(classId) => Promise>", "purpose": "重新生成邀请码"}, {"name": "setStudentEnrollmentStatusAction", "permission": "CLASS_ENROLL", "signature": "(classId, studentId, status) => Promise", "purpose": "设置学生状态"}, {"name": "createClassScheduleItemAction", "permission": "CLASS_SCHEDULE", "signature": "(prevState, formData) => Promise>", "purpose": "创建课表项"}, {"name": "updateClassScheduleItemAction", "permission": "CLASS_SCHEDULE", "signature": "(scheduleId, prevState, formData) => Promise", "purpose": "更新课表项"}, {"name": "deleteClassScheduleItemAction", "permission": "CLASS_SCHEDULE", "signature": "(scheduleId) => Promise", "purpose": "删除课表项"}, {"name": "createAdminClassAction", "permission": "CLASS_CREATE", "signature": "(prevState, formData) => Promise>", "purpose": "管理员创建班级"}, {"name": "updateAdminClassAction", "permission": "CLASS_UPDATE", "signature": "(classId, prevState, formData) => Promise", "purpose": "管理员更新班级"}, {"name": "deleteAdminClassAction", "permission": "CLASS_DELETE", "signature": "(classId) => Promise", "purpose": "管理员删除班级"} ], "dataAccess": [ {"name": "getTeacherClasses", "signature": "(params?: { teacherId?: string }) => Promise", "usedBy": ["teacher/classes/my", "dashboard"]}, {"name": "getAdminClasses", "signature": "() => Promise", "usedBy": ["admin班级管理"]}, {"name": "getGradeManagedClasses", "signature": "(userId) => Promise", "usedBy": ["grade_head班级管理"]}, {"name": "getStudentClasses", "signature": "(studentId) => Promise", "usedBy": ["student/dashboard"]}, {"name": "getStudentSchedule", "signature": "(studentId) => Promise", "usedBy": ["student课表"]}, {"name": "getClassStudents", "signature": "(params?: { classId?, q?, status?, teacherId? }) => Promise", "usedBy": ["teacher/classes/students"]}, {"name": "getClassSchedule", "signature": "(params?: { classId?, teacherId? }) => Promise", "usedBy": ["teacher/classes/schedule"]}, {"name": "getClassHomeworkInsights", "signature": "(params: { classId, teacherId?, limit? }) => Promise", "usedBy": ["classes作业洞察"]}, {"name": "getGradeHomeworkInsights", "signature": "(params: { gradeId, limit? }) => Promise", "usedBy": ["年级作业洞察"]}, {"name": "getTeacherIdForMutations", "signature": "() => Promise", "purpose": "获取当前教师ID(用于写操作)", "usedBy": ["classes写操作内部"]}, {"name": "getClassSubjects", "signature": "(classId: string) => Promise", "purpose": "获取班级学科列表", "usedBy": ["class-detail组件"]}, {"name": "getTeacherOptions", "signature": "() => Promise", "purpose": "获取教师选项列表", "usedBy": ["class-detail组件"]}, {"name": "getTeacherTeachingSubjects", "signature": "(teacherId: string) => Promise<...>", "purpose": "获取教师所教学科", "usedBy": ["classes内部"]}, {"name": "getManagedGrades", "signature": "(userId: string) => Promise<...>", "purpose": "获取所管年级", "usedBy": ["grade_head视图"]}, {"name": "getStudentsSubjectScores", "signature": "(...) => Promise<...>", "purpose": "获取学生学科成绩", "usedBy": ["classes内部"]}, {"name": "getClassStudentSubjectScoresV2", "signature": "(...) => Promise<...>", "purpose": "获取班级学生学科成绩V2", "usedBy": ["classes内部"]}, {"name": "createTeacherClass", "signature": "(input) => Promise", "purpose": "教师创建班级", "usedBy": ["createTeacherClassAction"]}, {"name": "createAdminClass", "signature": "(input) => Promise", "purpose": "管理员创建班级", "usedBy": ["createAdminClassAction"]}, {"name": "ensureClassInvitationCode", "signature": "(classId: string) => Promise<{ code: string }>", "purpose": "确保邀请码存在", "usedBy": ["ensureClassInvitationCodeAction"]}, {"name": "regenerateClassInvitationCode", "signature": "(classId: string) => Promise<{ code: string }>", "purpose": "重新生成邀请码", "usedBy": ["regenerateClassInvitationCodeAction"]}, {"name": "enrollStudentByInvitationCode", "signature": "(code: string, studentId: string) => Promise<{ classId: string }>", "purpose": "通过邀请码注册学生", "usedBy": ["joinClassByInvitationCodeAction"]}, {"name": "enrollTeacherByInvitationCode", "signature": "(code: string, teacherId: string) => Promise<...>", "purpose": "通过邀请码注册教师", "usedBy": ["classes内部"]}, {"name": "updateTeacherClass", "signature": "(classId: string, input) => Promise", "purpose": "教师更新班级", "usedBy": ["updateTeacherClassAction"]}, {"name": "updateAdminClass", "signature": "(classId: string, input) => Promise", "purpose": "管理员更新班级", "usedBy": ["updateAdminClassAction"]}, {"name": "setClassSubjectTeachers", "signature": "(classId: string, assignments: ClassSubjectTeacherAssignment[]) => Promise", "purpose": "设置班级学科教师", "usedBy": ["classes内部"]}, {"name": "deleteTeacherClass", "signature": "(classId: string) => Promise", "purpose": "教师删除班级", "usedBy": ["deleteTeacherClassAction"]}, {"name": "deleteAdminClass", "signature": "(classId: string) => Promise", "purpose": "管理员删除班级", "usedBy": ["deleteAdminClassAction"]}, {"name": "enrollStudentByEmail", "signature": "(classId: string, email: string) => Promise", "purpose": "通过邮箱注册学生", "usedBy": ["enrollStudentByEmailAction"]}, {"name": "setStudentEnrollmentStatus", "signature": "(classId: string, studentId: string, status: string) => Promise", "purpose": "设置学生状态", "usedBy": ["setStudentEnrollmentStatusAction"]}, {"name": "createClassScheduleItem", "signature": "(input: CreateClassScheduleItemInput) => Promise", "purpose": "创建课表项", "usedBy": ["createClassScheduleItemAction"]}, {"name": "updateClassScheduleItem", "signature": "(scheduleId: string, input: UpdateClassScheduleItemInput) => Promise", "purpose": "更新课表项", "usedBy": ["updateClassScheduleItemAction"]}, {"name": "deleteClassScheduleItem", "signature": "(scheduleId: string) => Promise", "purpose": "删除课表项", "usedBy": ["deleteClassScheduleItemAction"]} ], "types": [ {"name": "TeacherClass", "type": "type", "definition": "教师班级对象", "usedBy": ["getTeacherClasses", "dashboard"]}, {"name": "AssignmentSummary", "type": "type", "definition": "作业摘要", "usedBy": ["classes/components"]}, {"name": "TeacherOption", "type": "type", "definition": "教师选项", "usedBy": ["getTeacherOptions", "class-detail组件"]}, {"name": "DEFAULT_CLASS_SUBJECTS", "type": "const", "definition": "默认班级学科列表", "usedBy": ["classes内部"]}, {"name": "ClassSubject", "type": "type", "definition": "班级学科", "usedBy": ["getClassSubjects", "classes/components"]}, {"name": "ClassSubjectTeacherAssignment", "type": "type", "definition": "班级学科教师分配", "usedBy": ["setClassSubjectTeachers"]}, {"name": "AdminClassListItem", "type": "type", "definition": "管理员班级列表项", "usedBy": ["getAdminClasses", "getGradeManagedClasses"]}, {"name": "CreateTeacherClassInput", "type": "type", "definition": "教师创建班级输入", "usedBy": ["createTeacherClass"]}, {"name": "UpdateTeacherClassInput", "type": "type", "definition": "教师更新班级输入", "usedBy": ["updateTeacherClass"]}, {"name": "ClassStudent", "type": "type", "definition": "班级学生", "usedBy": ["getClassStudents", "classes/components"]}, {"name": "ClassScheduleItem", "type": "type", "definition": "班级课表项", "usedBy": ["getClassSchedule", "classes/components"]}, {"name": "CreateClassScheduleItemInput", "type": "type", "definition": "创建课表项输入", "usedBy": ["createClassScheduleItem"]}, {"name": "UpdateClassScheduleItemInput", "type": "type", "definition": "更新课表项输入", "usedBy": ["updateClassScheduleItem"]}, {"name": "StudentEnrolledClass", "type": "type", "definition": "学生已注册班级", "usedBy": ["getStudentClasses", "dashboard"]}, {"name": "StudentScheduleItem", "type": "type", "definition": "学生课表项", "usedBy": ["getStudentSchedule", "dashboard"]}, {"name": "ScoreStats", "type": "type", "definition": "成绩统计", "usedBy": ["classes/components"]}, {"name": "ClassHomeworkAssignmentStats", "type": "type", "definition": "班级作业统计", "usedBy": ["classes/components"]}, {"name": "ClassHomeworkInsights", "type": "type", "definition": "班级作业洞察", "usedBy": ["getClassHomeworkInsights", "classes/components"]}, {"name": "GradeHomeworkClassSummary", "type": "type", "definition": "年级作业班级汇总", "usedBy": ["classes/components"]}, {"name": "GradeHomeworkInsights", "type": "type", "definition": "年级作业洞察", "usedBy": ["getGradeHomeworkInsights", "classes/components"]} ], "components": [ {"name": "StudentsTable", "purpose": "学生表格"}, {"name": "StudentsFilters", "purpose": "学生筛选器"}, {"name": "ScheduleView", "purpose": "课表视图"}, {"name": "MyClassesGrid", "purpose": "我的班级网格"}, {"name": "AdminClassesClient", "purpose": "管理员班级客户端"}, {"name": "ScheduleFilters", "purpose": "课表筛选器"}, {"name": "GradeClassesClient", "purpose": "年级班级客户端"}, {"name": "transformAssignmentsToChartData", "file": "class-detail/transformAssignmentsToChartData", "type": "function", "purpose": "转换作业为图表数据"}, {"name": "ClassSubmissionTrendChart", "file": "class-detail/ClassSubmissionTrendChart", "purpose": "班级提交趋势图表"}, {"name": "ClassTrendsWidget", "file": "class-detail/ClassTrendsWidget", "purpose": "班级趋势组件"}, {"name": "ClassStudentsWidget", "file": "class-detail/ClassStudentsWidget", "purpose": "班级学生组件"}, {"name": "ClassScheduleGrid", "file": "class-detail/ClassScheduleGrid", "purpose": "班级课表网格"}, {"name": "ClassScheduleWidget", "file": "class-detail/ClassScheduleWidget", "purpose": "班级课表组件"}, {"name": "ClassQuickActions", "file": "class-detail/ClassQuickActions", "purpose": "班级快捷操作"}, {"name": "EditClassDialog", "file": "class-detail/EditClassDialog", "purpose": "编辑班级对话框"}, {"name": "ClassOverviewStats", "file": "class-detail/ClassOverviewStats", "purpose": "班级概览统计"}, {"name": "ClassHeader", "file": "class-detail/ClassHeader", "purpose": "班级头部"}, {"name": "ClassAssignmentsWidget", "file": "class-detail/ClassAssignmentsWidget", "purpose": "班级作业组件"} ] } }, "school": { "path": "src/modules/school", "description": "学校基础数据管理:学校、年级、部门、学年的CRUD。学校CRUD actions在写操作成功后调用logAudit()记录操作日志", "exports": { "actions": [ {"name": "createSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(prevState, formData) => Promise>", "purpose": "创建学校", "auditLog": "school.create"}, {"name": "updateSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(schoolId, prevState, formData) => Promise>", "purpose": "更新学校", "auditLog": "school.update"}, {"name": "deleteSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(schoolId) => Promise>", "purpose": "删除学校", "auditLog": "school.delete"}, {"name": "createGradeAction", "permission": "GRADE_MANAGE", "signature": "(prevState, formData) => Promise>", "purpose": "创建年级"}, {"name": "updateGradeAction", "permission": "GRADE_MANAGE", "signature": "(gradeId, prevState, formData) => Promise>", "purpose": "更新年级"}, {"name": "deleteGradeAction", "permission": "GRADE_MANAGE", "signature": "(gradeId) => Promise>", "purpose": "删除年级"}, {"name": "createDepartmentAction", "permission": "SCHOOL_MANAGE", "signature": "(prevState, formData) => Promise>", "purpose": "创建部门"}, {"name": "updateDepartmentAction", "permission": "SCHOOL_MANAGE", "signature": "(departmentId, prevState, formData) => Promise>", "purpose": "更新部门"}, {"name": "deleteDepartmentAction", "permission": "SCHOOL_MANAGE", "signature": "(departmentId) => Promise>", "purpose": "删除部门"}, {"name": "createAcademicYearAction", "permission": "SCHOOL_MANAGE", "signature": "(prevState, formData) => Promise>", "purpose": "创建学年"}, {"name": "updateAcademicYearAction", "permission": "SCHOOL_MANAGE", "signature": "(academicYearId, prevState, formData) => Promise>", "purpose": "更新学年"}, {"name": "deleteAcademicYearAction", "permission": "SCHOOL_MANAGE", "signature": "(academicYearId) => Promise>", "purpose": "删除学年"} ], "dataAccess": [ {"name": "getSchools", "signature": "() => Promise", "usedBy": ["admin学校管理", "onboarding"]}, {"name": "getGrades", "signature": "() => Promise", "usedBy": ["admin年级管理", "exams", "onboarding"]}, {"name": "getDepartments", "signature": "() => Promise", "usedBy": ["admin部门管理"]}, {"name": "getAcademicYears", "signature": "() => Promise", "usedBy": ["admin学年管理"]}, {"name": "getStaffOptions", "signature": "() => Promise", "usedBy": ["school组件"]}, {"name": "getGradesForStaff", "signature": "(staffId) => Promise", "usedBy": ["grade_head视图"]} ], "schema": [ {"name": "UpsertDepartmentSchema", "type": "const", "description": "zod schema 部门upsert", "usedBy": ["createDepartmentAction", "updateDepartmentAction"]}, {"name": "UpsertAcademicYearSchema", "type": "const", "description": "zod schema 学年upsert", "usedBy": ["createAcademicYearAction", "updateAcademicYearAction"]}, {"name": "UpsertSchoolSchema", "type": "const", "description": "zod schema 学校upsert", "usedBy": ["createSchoolAction", "updateSchoolAction"]}, {"name": "UpsertGradeSchema", "type": "const", "description": "zod schema 年级upsert", "usedBy": ["createGradeAction", "updateGradeAction"]} ], "types": [ {"name": "DepartmentListItem", "type": "type", "definition": "部门列表项", "usedBy": ["getDepartments", "school/components"]}, {"name": "AcademicYearListItem", "type": "type", "definition": "学年列表项", "usedBy": ["getAcademicYears", "school/components"]}, {"name": "SchoolListItem", "type": "type", "definition": "学校列表项", "usedBy": ["getSchools", "school/components"]}, {"name": "StaffOption", "type": "type", "definition": "员工选项", "usedBy": ["getStaffOptions", "school/components"]}, {"name": "GradeListItem", "type": "type", "definition": "年级列表项", "usedBy": ["getGrades", "school/components", "exams"]} ], "components": [ {"name": "SchoolsClient", "purpose": "学校管理客户端"}, {"name": "GradesClient", "purpose": "年级管理客户端"}, {"name": "DepartmentsClient", "purpose": "部门管理客户端"}, {"name": "AcademicYearClient", "purpose": "学年管理客户端"} ] } }, "dashboard": { "path": "src/modules/dashboard", "description": "各角色仪表盘数据聚合与展示", "exports": { "dataAccess": [ {"name": "getAdminDashboardData", "signature": "(scope?: DataScope) => Promise", "deps": ["shared/db", "DataScope"], "usedBy": ["admin/dashboard/page.tsx"]} ], "types": [ {"name": "StudentDashboardProps", "definition": "{ studentName, enrolledClassCount, dueSoonCount, overdueCount, gradedCount, todayScheduleItems, upcomingAssignments, grades }", "deps": ["homework/types.StudentDashboardGradeProps"], "usedBy": ["student-dashboard-view.tsx"]}, {"name": "TeacherDashboardData", "definition": "{ classes, schedule, assignments, submissions, teacherName, gradeTrends }", "deps": ["homework/data-access.getTeacherGradeTrends", "classes/data-access.getTeacherClasses"], "usedBy": ["teacher-dashboard-view.tsx"]}, {"name": "AdminDashboardData", "definition": "{ activeSessionsCount, userCount, userRoleCounts, classCount, ... }", "usedBy": ["admin/dashboard/page.tsx"]}, {"name": "AdminDashboardUserRoleCount", "type": "type", "definition": "管理员仪表盘用户角色计数", "usedBy": ["admin-dashboard/AdminDashboardView"]}, {"name": "AdminDashboardRecentUser", "type": "type", "definition": "管理员仪表盘最近用户", "usedBy": ["admin-dashboard/AdminDashboardView"]}, {"name": "StudentTodayScheduleItem", "type": "type", "definition": "学生今日课表项", "usedBy": ["student-dashboard/StudentTodayScheduleCard"]}, {"name": "TeacherTodayScheduleItem", "type": "type", "definition": "教师今日课表项", "usedBy": ["teacher-dashboard/TeacherSchedule"]} ], "components": [ {"name": "AdminDashboardView", "file": "admin-dashboard/AdminDashboardView", "purpose": "管理员仪表盘视图"}, {"name": "StudentDashboard", "file": "student-dashboard/StudentDashboard", "purpose": "学生仪表盘(注意:非StudentDashboardView)"}, {"name": "StudentDashboardHeader", "file": "student-dashboard/StudentDashboardHeader", "purpose": "学生仪表盘头部"}, {"name": "StudentGradesCard", "file": "student-dashboard/StudentGradesCard", "purpose": "学生成绩卡片"}, {"name": "StudentStatsGrid", "file": "student-dashboard/StudentStatsGrid", "purpose": "学生统计网格"}, {"name": "StudentTodayScheduleCard", "file": "student-dashboard/StudentTodayScheduleCard", "purpose": "学生今日课表卡片"}, {"name": "StudentUpcomingAssignmentsCard", "file": "student-dashboard/StudentUpcomingAssignmentsCard", "purpose": "学生即将到来作业卡片"}, {"name": "TeacherDashboardView", "file": "teacher-dashboard/TeacherDashboardView", "purpose": "教师仪表盘视图"}, {"name": "TeacherClassesCard", "file": "teacher-dashboard/TeacherClassesCard", "purpose": "教师班级卡片"}, {"name": "TeacherDashboardHeader", "file": "teacher-dashboard/TeacherDashboardHeader", "purpose": "教师仪表盘头部"}, {"name": "TeacherGradeTrends", "file": "teacher-dashboard/TeacherGradeTrends", "purpose": "教师年级趋势"}, {"name": "TeacherHomeworkCard", "file": "teacher-dashboard/TeacherHomeworkCard", "purpose": "教师作业卡片"}, {"name": "TeacherQuickActions", "file": "teacher-dashboard/TeacherQuickActions", "purpose": "教师快捷操作"}, {"name": "TeacherSchedule", "file": "teacher-dashboard/TeacherSchedule", "purpose": "教师课表"}, {"name": "TeacherStats", "file": "teacher-dashboard/TeacherStats", "purpose": "教师统计"}, {"name": "RecentSubmissions", "file": "teacher-dashboard/RecentSubmissions", "purpose": "最近提交"} ] } }, "layout": { "path": "src/modules/layout", "description": "应用布局框架:侧边栏、顶栏、导航配置", "exports": { "components": [ {"name": "AppSidebar", "purpose": "根据权限渲染侧边栏导航", "internalDeps": ["usePermission", "NAV_CONFIG"]}, {"name": "SiteHeader", "purpose": "顶部导航栏(集成 GlobalSearch 全局搜索:Cmd/Ctrl+K 唤起、300ms 防抖、↑/↓ 导航、Enter 跳转;NotificationDropdown 通知下拉)", "internalDeps": ["useSession", "signOut", "shared/components/global-search.GlobalSearch", "messaging/components/notification-dropdown.NotificationDropdown"]}, {"name": "SidebarProvider", "props": "{ children, sidebar }", "purpose": "侧边栏上下文Provider"}, {"name": "useSidebar", "type": "hook", "purpose": "侧边栏状态Hook"} ], "types": [ {"name": "Role", "type": "type", "definition": "\"admin\" | \"teacher\" | \"student\" | \"parent\"", "usedBy": ["NAV_CONFIG", "usePermission"]}, {"name": "NavItem", "type": "type", "definition": "{ title, href, icon?, permission? }", "usedBy": ["NAV_CONFIG", "AppSidebar"]} ], "config": [ {"name": "NAV_CONFIG", "type": "Record", "note": "每个NavItem含permission字段用于权限过滤。admin角色菜单包含Audit Logs项(icon: ScrollText, href: /admin/audit-logs, permission: AUDIT_LOG_READ),含子项Operation Logs与Login Logs。admin角色菜单的School Management子菜单包含Import Users项(href: /admin/users/import, permission: USER_MANAGE)。admin角色菜单包含Scheduling项(icon: CalendarClock, href: /admin/scheduling/rules, permission: SCHEDULE_ADJUST),含子项Rules(/admin/scheduling/rules, permission: SCHEDULE_ADJUST)、Auto Schedule(/admin/scheduling/auto, permission: SCHEDULE_AUTO)、Change Requests(/admin/scheduling/changes, permission: SCHEDULE_ADJUST)。teacher角色菜单包含Grades项(icon: GraduationCap, permission: GRADE_RECORD_READ),含子项All Grades(/teacher/grades)、Batch Entry(/teacher/grades/entry, permission: GRADE_RECORD_MANAGE)、Statistics(/teacher/grades/stats)。teacher角色菜单包含Schedule Changes项(icon: CalendarClock, href: /teacher/schedule-changes, permission: SCHEDULE_ADJUST)。teacher角色菜单包含Diagnostic项(icon: Stethoscope, href: /teacher/diagnostic, permission: DIAGNOSTIC_READ)。student角色菜单包含My Grades项(icon: GraduationCap, href: /student/grades, permission: GRADE_RECORD_READ)。student角色菜单包含Diagnostic项(icon: Stethoscope, href: /student/diagnostic, permission: DIAGNOSTIC_READ)。parent角色菜单包含Dashboard项(icon: LayoutDashboard, href: /parent/dashboard,无permission字段仅需登录)、Grades项(icon: GraduationCap, href: /parent/grades, permission: GRADE_RECORD_READ)、Announcements项(icon: Megaphone, href: /announcements, permission: ANNOUNCEMENT_READ)"} ] } }, "settings": { "path": "src/modules/settings", "description": "系统设置:AI Provider配置、用户偏好、密码安全(修改密码、强度校验)", "exports": { "actions": [ {"name": "getAiProviderSummaries", "permission": "AI_CONFIGURE", "signature": "() => Promise", "purpose": "获取AI Provider列表"}, {"name": "upsertAiProviderAction", "permission": "AI_CONFIGURE", "signature": "(data) => Promise>", "purpose": "创建/更新AI Provider", "deps": ["shared/lib/ai (encrypt/decrypt)"]}, {"name": "testAiProviderAction", "permission": "AI_CONFIGURE", "signature": "(data) => Promise>", "purpose": "测试AI Provider连通性", "deps": ["shared/lib/ai.testAiProviderConfig"]}, {"name": "changePasswordAction", "file": "actions-password.ts", "permission": "requireAuth()", "signature": "(prevState: ActionState, formData: FormData) => Promise>", "purpose": "修改当前用户密码(校验当前密码、新密码策略、速率限制 PASSWORD_CHANGE: 5次/分钟)", "deps": ["requireAuth", "validatePassword", "rateLimit", "bcryptjs (hash/compare)", "shared/db (users, passwordSecurity)"], "usedBy": ["components/password-change-form.tsx"]} ], "types": [ {"name": "AiProviderSummary", "type": "type", "definition": "AI Provider摘要", "usedBy": ["getAiProviderSummaries", "settings/components"]} ], "components": [ {"name": "AiProviderSettingsCard", "purpose": "AI Provider设置卡片"}, {"name": "AdminSettingsView", "purpose": "管理员设置视图(General/Appearance/Security/Notifications tab,Security 含 PasswordChangeForm,Notifications 含 NotificationPreferencesForm)"}, {"name": "ProfileSettingsForm", "purpose": "个人资料设置表单"}, {"name": "ThemePreferencesCard", "purpose": "主题偏好卡片"}, {"name": "StudentSettingsView", "purpose": "学生设置视图(含 Notifications tab)"}, {"name": "TeacherSettingsView", "purpose": "教师设置视图(含 Notifications tab)"}, {"name": "PasswordChangeForm", "purpose": "密码修改表单(当前密码/新密码/确认密码 + 强度指示器 + 需求提示)", "deps": ["changePasswordAction", "getPasswordStrength", "PASSWORD_REQUIREMENT_HINTS"]}, {"name": "NotificationPreferencesForm", "file": "components/notification-preferences-form.tsx", "purpose": "通知偏好设置表单(Switch 切换 email/sms/push 通道 + 5 个分类开关:作业/成绩/公告/消息/考勤;隐藏 checkbox 与 Switch 同步,useActionState 调用 updateNotificationPreferencesAction)", "deps": ["updateNotificationPreferencesAction", "shared/components/ui/switch", "shared/components/ui/card", "react.useActionState"], "usedBy": ["AdminSettingsView", "TeacherSettingsView", "StudentSettingsView"]} ] } }, "users": { "path": "src/modules/users", "description": "用户个人资料管理 + 用户批量导入/导出(Excel)", "exports": { "actions": [ { "name": "updateUserProfile", "signature": "(data: UpdateUserProfileInput) => Promise", "file": "actions.ts", "permission": "requireAuth()", "deps": ["shared.db", "shared.db.schema.users", "shared.lib.auth-guard.requireAuth"] }, { "name": "UpdateUserProfileInput", "type": "type", "file": "actions.ts", "definition": "{ name?, phone?, address?, gender?, age? }" }, { "name": "downloadUserTemplateAction", "signature": "() => Promise>", "file": "actions.ts", "permission": "USER_MANAGE", "purpose": "生成用户导入模板(返回 base64 编码的 Excel)", "deps": ["requirePermission", "import-export.generateUserImportTemplate"], "usedBy": ["components/user-import-dialog.tsx"] }, { "name": "importUsersAction", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "permission": "USER_MANAGE", "purpose": "导入用户:接收文件,解析+验证+批量创建(默认密码 123456)", "deps": ["requirePermission", "shared.lib.excel.parseExcel", "import-export.parseUserImportData", "import-export.batchImportUsers"], "usedBy": ["components/user-import-dialog.tsx"] }, { "name": "exportUsersAction", "signature": "(role?: string) => Promise>", "file": "actions.ts", "permission": "USER_MANAGE", "purpose": "导出用户列表(返回 base64 编码的 Excel)", "deps": ["requirePermission", "import-export.exportUsersToExcel"], "usedBy": ["待扩展"] } ], "dataAccess": [ { "name": "getUserProfile", "signature": "(userId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.users"] }, { "name": "UserProfile", "type": "type", "file": "data-access.ts", "definition": "{ id, name, email, image, role, phone, address, gender, age, onboardedAt, createdAt, updatedAt }" } ], "importExport": [ { "name": "generateUserImportTemplate", "signature": "() => Promise", "file": "import-export.ts", "purpose": "生成用户导入模板(列:姓名/邮箱/角色/手机/班级邀请码,含示例行)", "deps": ["shared.lib.excel.generateTemplate"], "usedBy": ["actions.downloadUserTemplateAction"] }, { "name": "parseUserImportData", "signature": "(rows: Record[]) => UserImportValidation", "file": "import-export.ts", "purpose": "解析并验证导入行(校验姓名/邮箱格式/角色枚举/邀请码仅 student)", "deps": [], "usedBy": ["actions.importUsersAction"] }, { "name": "batchImportUsers", "signature": "(records: UserImportRecord[]) => Promise", "file": "import-export.ts", "purpose": "批量创建用户(默认密码 123456 bcrypt 哈希,自动创建 usersToRoles,student 通过邀请码自动加入班级)", "deps": ["shared.db", "shared.db.schema.users", "shared.db.schema.roles", "shared.db.schema.usersToRoles", "shared.db.schema.classes", "shared.db.schema.classEnrollments", "bcryptjs", "@paralleldrive/cuid2"], "usedBy": ["actions.importUsersAction"] }, { "name": "exportUsersToExcel", "signature": "(params: { scope: DataScope; role?: string }) => Promise", "file": "import-export.ts", "purpose": "导出用户列表到 Excel(含姓名/邮箱/手机/性别/年龄/角色/创建时间)", "deps": ["shared.db", "shared.db.schema.users", "shared.db.schema.roles", "shared.db.schema.usersToRoles", "shared.lib.excel.exportToExcel"], "usedBy": ["actions.exportUsersAction", "app/api/export/route.ts"] } ], "types": [ { "name": "UserImportRecord", "type": "type", "file": "import-export.ts", "definition": "{ name, email, role, phone?, invitationCode? }", "usedBy": ["parseUserImportData", "batchImportUsers"] }, { "name": "UserImportValidation", "type": "type", "file": "import-export.ts", "definition": "{ valid: UserImportRecord[], invalid: Array<{ row, record, errors }> }", "usedBy": ["parseUserImportData"] }, { "name": "UserImportResult", "type": "type", "file": "import-export.ts", "definition": "{ successCount, failedCount, errors: Array<{ row, email, error }> }", "usedBy": ["batchImportUsers", "importUsersAction"] } ], "components": [ { "name": "UserImportDialog", "file": "components/user-import-dialog.tsx", "purpose": "用户批量导入对话框(4 状态:idle/preview/importing/done;下载模板→上传预览→确认导入→结果展示)", "usedBy": ["app/(dashboard)/admin/users/import/page.tsx"] } ] } }, "audit": { "path": "src/modules/audit", "description": "操作日志、登录日志与数据变更日志查询,支持 Excel 导出", "exports": { "dataAccess": [ { "name": "getAuditLogs", "signature": "(params?: AuditLogQueryParams) => Promise>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.auditLogs"], "usedBy": ["app/(dashboard)/admin/audit-logs/page.tsx"] }, { "name": "getLoginLogs", "signature": "(params?: LoginLogQueryParams) => Promise>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.loginLogs"], "usedBy": ["app/(dashboard)/admin/audit-logs/login-logs/page.tsx"] }, { "name": "getAuditModuleOptions", "signature": "() => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.auditLogs"], "usedBy": ["app/(dashboard)/admin/audit-logs/page.tsx"] }, { "name": "getDataChangeLogs", "signature": "(params?: DataChangeLogQueryParams) => Promise>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.dataChangeLogs"], "usedBy": ["getDataChangeLogsAction"] }, { "name": "getDataChangeStats", "signature": "() => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.dataChangeLogs"], "usedBy": ["getDataChangeLogsAction"] }, { "name": "getDataChangeTableOptions", "signature": "() => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.dataChangeLogs"], "usedBy": ["getDataChangeLogsAction"] }, { "name": "getDataChangeLogsForExport", "signature": "(params?: DataChangeLogQueryParams) => Promise", "file": "data-access.ts", "deps": ["getDataChangeLogs"], "usedBy": ["exportDataChangeLogsAction"] }, { "name": "getAuditLogsForExport", "signature": "(params?: AuditLogQueryParams) => Promise", "file": "data-access.ts", "deps": ["getAuditLogs"], "usedBy": ["exportAuditLogsAction"] }, { "name": "getLoginLogsForExport", "signature": "(params?: LoginLogQueryParams) => Promise", "file": "data-access.ts", "deps": ["getLoginLogs"], "usedBy": ["exportLoginLogsAction"] } ], "actions": [ { "name": "getDataChangeLogsAction", "permission": "AUDIT_LOG_READ", "signature": "(params?: DataChangeLogQueryParams) => Promise>", "file": "actions.ts", "purpose": "获取数据变更日志(分页结果 + tableOptions + stats 三者并行加载)", "deps": ["requirePermission", "data-access.getDataChangeLogs", "data-access.getDataChangeTableOptions", "data-access.getDataChangeStats"], "usedBy": ["待扩展"] }, { "name": "exportAuditLogsAction", "permission": "AUDIT_LOG_READ", "signature": "(params?: AuditLogQueryParams) => Promise>", "file": "actions.ts", "purpose": "导出操作日志为 Excel", "deps": ["requirePermission", "data-access.getAuditLogsForExport", "shared.lib.excel.exportToExcel"], "usedBy": ["待扩展"] }, { "name": "exportLoginLogsAction", "permission": "AUDIT_LOG_READ", "signature": "(params?: LoginLogQueryParams) => Promise>", "file": "actions.ts", "purpose": "导出登录日志为 Excel", "deps": ["requirePermission", "data-access.getLoginLogsForExport", "shared.lib.excel.exportToExcel"], "usedBy": ["待扩展"] }, { "name": "exportDataChangeLogsAction", "permission": "AUDIT_LOG_READ", "signature": "(params?: DataChangeLogQueryParams) => Promise>", "file": "actions.ts", "purpose": "导出数据变更日志为 Excel", "deps": ["requirePermission", "data-access.getDataChangeLogsForExport", "shared.lib.excel.exportToExcel"], "usedBy": ["待扩展"] } ], "types": [ { "name": "AuditLog", "type": "interface", "file": "types.ts", "definition": "{ id, userId, userName, action, module, targetId, targetType, detail, ipAddress, userAgent, status, createdAt }" }, { "name": "LoginLog", "type": "interface", "file": "types.ts", "definition": "{ id, userId, userEmail, action, status, ipAddress, userAgent, errorMessage, createdAt }" }, { "name": "AuditLogQueryParams", "type": "type", "file": "types.ts", "definition": "{ userId?, module?, action?, status?, page?, pageSize?, startDate?, endDate? }" }, { "name": "LoginLogQueryParams", "type": "type", "file": "types.ts", "definition": "{ userId?, action?, status?, page?, pageSize?, startDate?, endDate? }" }, { "name": "PaginatedResult", "type": "interface", "file": "types.ts", "definition": "{ items: T[], total, page, pageSize, totalPages }" }, { "name": "DataChangeAction", "type": "type", "file": "types.ts", "definition": "'create' | 'update' | 'delete'", "usedBy": ["data-access", "shared/lib/change-logger", "DataChangeLog"] }, { "name": "DataChangeLog", "type": "interface", "file": "types.ts", "definition": "{ id, tableName, recordId, action, oldValue, newValue, changedBy, changedByName, ipAddress, createdAt }", "usedBy": ["audit/data-access", "audit/actions"] }, { "name": "DataChangeStat", "type": "interface", "file": "types.ts", "definition": "{ tableName: string, count: number }", "usedBy": ["getDataChangeStats", "getDataChangeLogsAction"] }, { "name": "DataChangeLogQueryParams", "type": "type", "file": "types.ts", "definition": "{ tableName?, recordId?, action?, userId?, page?, pageSize?, startDate?, endDate? }", "usedBy": ["getDataChangeLogs", "getDataChangeLogsForExport", "getDataChangeLogsAction", "exportDataChangeLogsAction"] } ], "components": [ { "name": "AuditLogTable", "file": "components/audit-log-table.tsx", "purpose": "操作日志表格(分页)" }, { "name": "AuditLogFilters", "file": "components/audit-log-filters.tsx", "purpose": "操作日志筛选器(模块/操作/状态/日期)" }, { "name": "AuditLogView", "file": "components/audit-log-view.tsx", "purpose": "操作日志视图(筛选+表格+分页)" }, { "name": "LoginLogTable", "file": "components/login-log-table.tsx", "purpose": "登录日志表格(分页)" }, { "name": "LoginLogFilters", "file": "components/login-log-filters.tsx", "purpose": "登录日志筛选器(操作/状态/日期)" }, { "name": "LoginLogView", "file": "components/login-log-view.tsx", "purpose": "登录日志视图(筛选+表格+分页)" } ] } }, "announcements": { "path": "src/modules/announcements", "description": "通知公告系统:创建、编辑、发布、归档、删除公告,所有登录用户可查看已发布公告", "exports": { "actions": [ { "name": "createAnnouncementAction", "permission": "ANNOUNCEMENT_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "创建公告(草稿/已发布)", "deps": ["requirePermission", "shared/db"], "usedBy": ["announcement-form.tsx"] }, { "name": "updateAnnouncementAction", "permission": "ANNOUNCEMENT_MANAGE", "signature": "(id: string, prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "更新公告", "deps": ["requirePermission", "shared/db"], "usedBy": ["announcement-form.tsx"] }, { "name": "deleteAnnouncementAction", "permission": "ANNOUNCEMENT_MANAGE", "signature": "(id: string) => Promise>", "purpose": "删除公告", "deps": ["requirePermission", "shared/db"], "usedBy": ["announcement-detail.tsx"] }, { "name": "publishAnnouncementAction", "permission": "ANNOUNCEMENT_MANAGE", "signature": "(id: string) => Promise>", "purpose": "发布公告", "deps": ["requirePermission", "shared/db"], "usedBy": ["announcement-detail.tsx"] }, { "name": "archiveAnnouncementAction", "permission": "ANNOUNCEMENT_MANAGE", "signature": "(id: string) => Promise>", "purpose": "归档公告", "deps": ["requirePermission", "shared/db"], "usedBy": ["announcement-detail.tsx"] }, { "name": "getAnnouncementsAction", "permission": "requireAuth", "signature": "(params?: GetAnnouncementsParams) => Promise>", "purpose": "获取公告列表(所有登录用户可读)", "deps": ["requireAuth", "data-access.getAnnouncements"], "usedBy": ["待扩展"] } ], "dataAccess": [ { "name": "getAnnouncements", "signature": "(params?: { status?, type?, page?, pageSize? }) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.announcements"], "usedBy": ["admin/announcements/page.tsx", "announcements/page.tsx"] }, { "name": "getAnnouncementById", "signature": "(id: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.announcements"], "usedBy": ["admin/announcements/[id]/page.tsx"] } ], "schemas": [ { "name": "CreateAnnouncementSchema", "type": "zod", "file": "schema.ts", "definition": "{ title, content, type?, status?, targetGradeId?, targetClassId?, publishedAt? }", "usedBy": ["createAnnouncementAction"] }, { "name": "UpdateAnnouncementSchema", "type": "zod", "file": "schema.ts", "definition": "{ title, content, type?, status?, targetGradeId?, targetClassId?, publishedAt? }", "usedBy": ["updateAnnouncementAction"] } ], "types": [ { "name": "Announcement", "type": "interface", "file": "types.ts", "definition": "{ id, title, content, type, status, targetGradeId, targetClassId, authorId, authorName, publishedAt, createdAt, updatedAt }", "usedBy": ["announcements/components", "页面"] }, { "name": "AnnouncementListItem", "type": "type", "file": "types.ts", "definition": "= Announcement", "usedBy": ["列表页"] }, { "name": "AnnouncementStatus", "type": "type", "file": "types.ts", "definition": "\"draft\" | \"published\" | \"archived\"", "usedBy": ["data-access", "components"] }, { "name": "AnnouncementType", "type": "type", "file": "types.ts", "definition": "\"school\" | \"grade\" | \"class\"", "usedBy": ["data-access", "components"] }, { "name": "GetAnnouncementsParams", "type": "interface", "file": "types.ts", "definition": "{ status?, type?, page?, pageSize? }", "usedBy": ["getAnnouncements", "getAnnouncementsAction"] } ], "components": [ { "name": "AnnouncementList", "file": "components/announcement-list.tsx", "purpose": "公告列表(支持状态筛选)" }, { "name": "AnnouncementCard", "file": "components/announcement-card.tsx", "purpose": "单条公告卡片" }, { "name": "AnnouncementForm", "file": "components/announcement-form.tsx", "purpose": "创建/编辑表单" }, { "name": "AnnouncementDetail", "file": "components/announcement-detail.tsx", "purpose": "详情查看(含发布/归档/删除操作)" }, { "name": "AdminAnnouncementsView", "file": "components/admin-announcements-view.tsx", "purpose": "管理端公告视图(列表+创建对话框)" } ] } }, "files": { "path": "src/modules/files", "description": "文件上传与管理:通过 API 路由处理文件上传(保存到 public/uploads/YYYY-MM/),记录文件元数据到 DB,支持按关联资源(exam/textbook/question/announcement)多态查询、下载与删除", "exports": { "dataAccess": [ { "name": "createFileAttachment", "signature": "(data: CreateFileAttachmentInput) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["app/api/upload/route.ts"] }, { "name": "getFileAttachment", "signature": "(id: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["app/api/files/[id]/route.ts"] }, { "name": "getFileAttachmentsByTarget", "signature": "(targetType: string, targetId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["按关联资源查询文件列表"] }, { "name": "getFileAttachmentsByUploader", "signature": "(uploaderId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["按上传者查询文件列表"] }, { "name": "getAllFileAttachments", "signature": "(limit?: number) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["app/(dashboard)/admin/files/page.tsx"] }, { "name": "deleteFileAttachment", "signature": "(id: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["app/api/files/[id]/route.ts"] }, { "name": "deleteFileAttachments", "signature": "(ids: string[]) => Promise", "file": "data-access.ts", "purpose": "批量删除文件附件记录(仅删 DB 行,磁盘文件由调用方处理;失败时回退到逐条删除)", "deps": ["shared.db", "shared.db.schema.fileAttachments", "drizzle-orm.inArray"], "usedBy": ["app/api/files/batch-delete/route.ts"] }, { "name": "getFileAttachmentsWithFilters", "signature": "(params: FileAttachmentQueryParams) => Promise", "file": "data-access.ts", "purpose": "按 mimeType(精确或前缀匹配)与 search(originalName/filename 模糊匹配)筛选文件列表,支持 limit/offset 分页", "deps": ["shared.db", "shared.db.schema.fileAttachments", "drizzle-orm.like", "drizzle-orm.or", "drizzle-orm.and"], "usedBy": ["app/(dashboard)/admin/files/page.tsx"] }, { "name": "getFileStats", "signature": "() => Promise", "file": "data-access.ts", "purpose": "获取文件统计(总数、总大小、按 mimeType 分组的 count/size)", "deps": ["shared.db", "shared.db.schema.fileAttachments", "drizzle-orm.count", "drizzle-orm.sql"], "usedBy": ["app/(dashboard)/admin/files/page.tsx"] }, { "name": "getFileAttachmentsByIds", "signature": "(ids: string[]) => Promise", "file": "data-access.ts", "purpose": "按 ID 列表批量查询文件(用于批量删除前获取磁盘路径)", "deps": ["shared.db", "shared.db.schema.fileAttachments", "drizzle-orm.inArray"], "usedBy": ["app/api/files/batch-delete/route.ts"] } ], "types": [ { "name": "FileAttachment", "type": "interface", "file": "types.ts", "definition": "{ id, filename, originalName, mimeType, size, storagePath, url, uploaderId, targetType, targetId, createdAt }", "usedBy": ["files/components", "data-access", "API 路由"] }, { "name": "FileUploadResult", "type": "interface", "file": "types.ts", "definition": "{ id, url, filename, originalName, size, mimeType }", "usedBy": ["app/api/upload/route.ts 响应", "file-upload.tsx 回调"] }, { "name": "FileTargetType", "type": "type", "file": "types.ts", "definition": "\"exam\" | \"textbook\" | \"question\" | \"announcement\"", "usedBy": ["types.FileAttachment.targetType", "file-upload.tsx"] }, { "name": "CreateFileAttachmentInput", "type": "interface", "file": "types.ts", "definition": "{ id, filename, originalName, mimeType, size, storagePath, url, uploaderId, targetType?, targetId? }", "usedBy": ["createFileAttachment"] }, { "name": "FileAttachmentQueryParams", "type": "interface", "file": "types.ts", "definition": "{ mimeType?, search?, limit?, offset? }", "usedBy": ["getFileAttachmentsWithFilters"] }, { "name": "FileStats", "type": "interface", "file": "types.ts", "definition": "{ totalCount, totalSize, byType: Array<{ mimeType, count, size }> }", "usedBy": ["getFileStats"] }, { "name": "BatchDeleteResult", "type": "interface", "file": "types.ts", "definition": "{ success, deletedCount, failedIds: string[] }", "usedBy": ["deleteFileAttachments", "app/api/files/batch-delete/route.ts"] } ], "components": [ { "name": "FileUpload", "file": "components/file-upload.tsx", "purpose": "文件上传组件(拖拽+点击上传,进度条,文件类型校验,调用 /api/upload)" }, { "name": "FileList", "file": "components/file-list.tsx", "purpose": "文件列表展示(图标、文件名、大小、下载链接、删除按钮)" }, { "name": "FilePreview", "file": "components/file-preview.tsx", "purpose": "文件预览(图片直接预览,PDF iframe,其他下载)" }, { "name": "FileIcon", "file": "components/file-icon.tsx", "purpose": "根据 MIME 类型显示不同图标与颜色" }, { "name": "AdminFilesView", "file": "components/admin-files-view.tsx", "purpose": "管理端文件视图(上传+列表+删除)" } ] } }, "grades": { "path": "src/modules/grades", "description": "成绩分析模块:成绩录入(单条+批量)、查询(按班级/科目/考试/学期过滤)、统计报表(均分、中位数、标准差、及格率、优秀率、排名)、Excel 导出(成绩明细+统计汇总/班级多科目横向对比)、趋势对比分析(成绩趋势、班级对比、科目对比、分数分布、排名趋势)", "exports": { "dataAccess": [ { "name": "getGradeRecords", "signature": "(params: GradeQueryParams & { scope: DataScope; currentUserId?: string }) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords", "shared.db.schema.classes", "shared.db.schema.classEnrollments", "shared.db.schema.subjects", "shared.db.schema.users"], "usedBy": ["grades/actions.getGradeRecordsAction"] }, { "name": "getGradeRecordById", "signature": "(id: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/actions.getGradeRecordByIdAction"] }, { "name": "createGradeRecord", "signature": "(data: CreateGradeRecordInput, recordedBy: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/actions.createGradeRecordAction"] }, { "name": "batchCreateGradeRecords", "signature": "(data: BatchCreateGradeRecordInput, recordedBy: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/actions.batchCreateGradeRecordsAction"] }, { "name": "updateGradeRecord", "signature": "(id: string, data: UpdateGradeRecordInput) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/actions.updateGradeRecordAction"] }, { "name": "deleteGradeRecord", "signature": "(id: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/actions.deleteGradeRecordAction"] }, { "name": "getClassGradeStats", "signature": "(classId: string, subjectId?: string, examId?: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/data-access.getClassGradeStatsWithMeta"] }, { "name": "getClassGradeStatsWithMeta", "signature": "(classId: string, subjectId?: string, examId?: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords", "shared.db.schema.classes", "shared.db.schema.subjects"], "usedBy": ["grades/actions.getClassGradeStatsAction"] }, { "name": "getStudentGradeSummary", "signature": "(studentId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords", "shared.db.schema.subjects"], "usedBy": ["grades/actions.getStudentGradeSummaryAction"] }, { "name": "getClassRanking", "signature": "(classId: string, subjectId?: string, examId?: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords", "shared.db.schema.users"], "usedBy": ["grades/actions.getClassRankingAction"] }, { "name": "getClassStudentsForEntry", "signature": "(classId: string) => Promise<{ id: string; name: string }[]>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.classEnrollments", "shared.db.schema.users"], "usedBy": ["grades/components/batch-grade-entry"] }, { "name": "getGradeTrend", "signature": "(params: { studentId; subjectId?; semester?; scope: DataScope }) => Promise", "file": "data-access-analytics.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords", "shared.db.schema.classEnrollments"], "usedBy": ["grades/actions-analytics.getGradeTrendAction", "teacher/grades/analytics"] }, { "name": "getClassComparison", "signature": "(params: { gradeId; subjectId; examId?; scope: DataScope }) => Promise", "file": "data-access-analytics.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords", "shared.db.schema.classes"], "usedBy": ["grades/actions-analytics.getClassComparisonAction", "teacher/grades/analytics"] }, { "name": "getSubjectComparison", "signature": "(params: { classId; examId?; semester?; scope: DataScope }) => Promise", "file": "data-access-analytics.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords", "shared.db.schema.subjects"], "usedBy": ["grades/actions-analytics.getSubjectComparisonAction", "teacher/grades/analytics"] }, { "name": "getGradeDistribution", "signature": "(params: { classId; subjectId?; examId?; scope: DataScope }) => Promise", "file": "data-access-analytics.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/actions-analytics.getGradeDistributionAction", "teacher/grades/analytics"] }, { "name": "getRankingTrend", "signature": "(studentId: string, subjectId?, semester?) => Promise", "file": "data-access-ranking.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords", "shared.db.schema.classEnrollments"], "usedBy": ["grades/actions-analytics.getRankingTrendAction"] } ], "actions": [ { "name": "createGradeRecordAction", "signature": "(prevState, formData) => Promise>", "file": "actions.ts", "permission": "GRADE_RECORD_MANAGE", "usedBy": ["grades/components/grade-record-form"] }, { "name": "batchCreateGradeRecordsAction", "signature": "(prevState, formData) => Promise>", "file": "actions.ts", "permission": "GRADE_RECORD_MANAGE", "usedBy": ["grades/components/batch-grade-entry"] }, { "name": "updateGradeRecordAction", "signature": "(prevState, formData) => Promise>", "file": "actions.ts", "permission": "GRADE_RECORD_MANAGE", "usedBy": ["grades/components/grade-record-list"] }, { "name": "deleteGradeRecordAction", "signature": "(prevState, formData) => Promise>", "file": "actions.ts", "permission": "GRADE_RECORD_MANAGE", "usedBy": ["grades/components/grade-record-list"] }, { "name": "getGradeRecordsAction", "signature": "(params) => Promise", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "usedBy": ["teacher/grades/page"] }, { "name": "getClassGradeStatsAction", "signature": "(classId, subjectId?, examId?) => Promise", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "usedBy": ["teacher/grades/stats/page"] }, { "name": "getStudentGradeSummaryAction", "signature": "(studentId?) => Promise", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "usedBy": ["student/grades/page", "parent/grades/page"] }, { "name": "getClassRankingAction", "signature": "(classId, subjectId?, examId?) => Promise", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "usedBy": ["teacher/grades/stats/page"] }, { "name": "getGradeRecordByIdAction", "signature": "(id) => Promise", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "usedBy": ["grades/components/grade-record-list"] }, { "name": "exportGradesAction", "signature": "(params: { classId: string; subjectId?: string; examId?: string; reportType?: \"detail\" | \"class\" }) => Promise>", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "purpose": "导出成绩到 Excel(detail=成绩明细+统计汇总,class=班级多科目横向对比总表),返回 base64 buffer", "deps": ["requirePermission", "export.exportGradeRecordsToExcel", "export.exportClassGradeReportToExcel", "export.formatDateForFile"], "usedBy": ["grades/components/export-button.tsx"] }, { "name": "getGradeTrendAction", "signature": "(params) => Promise", "file": "actions-analytics.ts", "permission": "GRADE_RECORD_READ", "purpose": "获取成绩趋势(按学生/科目/学期,返回归一化分数趋势点)", "usedBy": ["teacher/grades/analytics"] }, { "name": "getClassComparisonAction", "signature": "(params) => Promise", "file": "actions-analytics.ts", "permission": "GRADE_RECORD_READ", "purpose": "获取班级对比(同年级各班的均分/及格率/优秀率)", "usedBy": ["teacher/grades/analytics"] }, { "name": "getSubjectComparisonAction", "signature": "(params) => Promise", "file": "actions-analytics.ts", "permission": "GRADE_RECORD_READ", "purpose": "获取科目对比(同班级各科目雷达图数据)", "usedBy": ["teacher/grades/analytics"] }, { "name": "getGradeDistributionAction", "signature": "(params) => Promise", "file": "actions-analytics.ts", "permission": "GRADE_RECORD_READ", "purpose": "获取分数分布(90-100/80-89/70-79/60-69/<60 各区间人数)", "usedBy": ["teacher/grades/analytics"] }, { "name": "getRankingTrendAction", "signature": "(studentId, subjectId?, semester?) => Promise", "file": "actions-analytics.ts", "permission": "GRADE_RECORD_READ", "purpose": "获取排名趋势(学生历次考试排名变化,含 DataScope 二次校验)", "usedBy": ["待扩展"] } ], "schemas": [ { "name": "CreateGradeRecordSchema", "type": "ZodSchema", "file": "schema.ts", "usedBy": ["createGradeRecordAction"] }, { "name": "BatchCreateGradeRecordSchema", "type": "ZodSchema", "file": "schema.ts", "usedBy": ["batchCreateGradeRecordsAction"] }, { "name": "UpdateGradeRecordSchema", "type": "ZodSchema", "file": "schema.ts", "usedBy": ["updateGradeRecordAction"] } ], "types": [ { "name": "GradeRecord", "type": "interface", "file": "types.ts", "usedBy": ["data-access", "actions"] }, { "name": "GradeRecordListItem", "type": "interface", "file": "types.ts", "usedBy": ["data-access", "actions", "components/grade-record-list"] }, { "name": "GradeStats", "type": "interface", "file": "types.ts", "definition": "{ count, average, median, stdDev, passRate, excellentRate, maxScore, minScore }", "usedBy": ["data-access", "components/grade-stats-card"] }, { "name": "ClassGradeStats", "type": "interface", "file": "types.ts", "usedBy": ["data-access", "actions", "components/class-grade-report"] }, { "name": "StudentGradeSummary", "type": "interface", "file": "types.ts", "usedBy": ["data-access", "actions", "components/student-grade-summary"] }, { "name": "ClassRankingItem", "type": "interface", "file": "types.ts", "usedBy": ["data-access", "actions", "components/class-grade-report"] }, { "name": "GradeRecordType", "type": "type", "file": "types.ts", "definition": "\"exam\" | \"quiz\" | \"assignment\" | \"monthly\" | \"midterm\" | \"final\"", "usedBy": ["types.GradeRecord.type"] }, { "name": "GradeRecordSemester", "type": "type", "file": "types.ts", "definition": "\"1\" | \"2\"", "usedBy": ["types.GradeRecord.semester"] }, { "name": "GradeQueryParams", "type": "interface", "file": "types.ts", "usedBy": ["data-access.getGradeRecords"] }, { "name": "GradeTrendPoint", "type": "interface", "file": "types.ts", "definition": "{ date, title, score, fullScore, normalizedScore, type }", "usedBy": ["data-access-analytics.getGradeTrend", "grade-trend-chart"] }, { "name": "GradeTrendResult", "type": "interface", "file": "types.ts", "definition": "{ label, points: GradeTrendPoint[], averageScore }", "usedBy": ["data-access-analytics.getGradeTrend", "grade-trend-chart"] }, { "name": "ClassComparisonItem", "type": "interface", "file": "types.ts", "definition": "{ classId, className, averageScore, passRate, excellentRate, studentCount }", "usedBy": ["data-access-analytics.getClassComparison", "class-comparison-chart"] }, { "name": "SubjectComparisonItem", "type": "interface", "file": "types.ts", "definition": "{ subjectId, subjectName, averageScore, passRate, excellentRate }", "usedBy": ["data-access-analytics.getSubjectComparison", "subject-comparison-chart"] }, { "name": "GradeDistributionBucket", "type": "interface", "file": "types.ts", "definition": "{ label, min, max, count, percentage }", "usedBy": ["data-access-analytics.getGradeDistribution", "grade-distribution-chart"] }, { "name": "GradeDistributionResult", "type": "interface", "file": "types.ts", "definition": "{ buckets: GradeDistributionBucket[], totalCount }", "usedBy": ["data-access-analytics.getGradeDistribution", "grade-distribution-chart"] }, { "name": "RankingTrendPoint", "type": "interface", "file": "types.ts", "definition": "{ title, date, rank, totalStudents, score }", "usedBy": ["data-access-ranking.getRankingTrend"] }, { "name": "RankingTrendResult", "type": "interface", "file": "types.ts", "definition": "{ studentName, points: RankingTrendPoint[] }", "usedBy": ["data-access-ranking.getRankingTrend"] } ], "importExport": [ { "name": "exportGradeRecordsToExcel", "signature": "(params: { classId: string; subjectId?: string; examId?: string; scope: DataScope }) => Promise", "file": "export.ts", "purpose": "导出成绩单(Sheet1 成绩明细,Sheet2 统计汇总:均分/中位数/最高分/最低分/标准差/及格率/优秀率/参考人数)", "deps": ["shared.lib.excel.exportToExcel", "data-access.getGradeRecords", "data-access.getClassGradeStats"], "usedBy": ["actions.exportGradesAction", "app/api/export/route.ts"] }, { "name": "exportClassGradeReportToExcel", "signature": "(params: { classId: string; scope: DataScope }) => Promise", "file": "export.ts", "purpose": "导出班级成绩总表(多科目横向对比,含总分/平均分/排名列)", "deps": ["shared.db", "shared.db.schema.classes", "shared.db.schema.subjects", "shared.db.schema.gradeRecords", "shared.db.schema.users", "shared.lib.excel.exportToExcel", "data-access.getGradeRecords"], "usedBy": ["actions.exportGradesAction"] }, { "name": "formatDateForFile", "signature": "(d?: Date) => string", "file": "export.ts", "purpose": "格式化日期为 YYYY-MM-DD 用于文件名", "deps": [], "usedBy": ["actions.exportGradesAction"] } ], "components": [ { "name": "GradeRecordForm", "file": "components/grade-record-form.tsx", "purpose": "单条成绩录入表单(选择学生、班级、科目、考试,输入分数、满分、类型、学期、备注)" }, { "name": "BatchGradeEntry", "file": "components/batch-grade-entry.tsx", "purpose": "批量录入界面(选择班级+科目+考试,表格形式录入每个学生分数)" }, { "name": "GradeRecordList", "file": "components/grade-record-list.tsx", "purpose": "成绩列表(含查询筛选、删除对话框)" }, { "name": "GradeStatsCard", "file": "components/grade-stats-card.tsx", "purpose": "统计卡片(均分、中位数、标准差、及格率、优秀率、最高分、最低分)" }, { "name": "GradeQueryFilters", "file": "components/grade-query-filters.tsx", "purpose": "查询筛选器(班级、科目、考试类型、学期)" }, { "name": "StudentGradeSummary", "file": "components/student-grade-summary.tsx", "purpose": "学生成绩汇总视图(按科目分组展示成绩趋势)" }, { "name": "ClassGradeReport", "file": "components/class-grade-report.tsx", "purpose": "班级成绩报表(含统计+排名)" }, { "name": "ExportButton", "file": "components/export-button.tsx", "purpose": "成绩导出按钮(DropdownMenu 选择 detail/class 报表类型,调用 exportGradesAction 并触发浏览器下载)", "usedBy": ["teacher/grades/page.tsx", "teacher/grades/stats/page.tsx"] }, { "name": "GradeTrendChart", "file": "components/grade-trend-chart.tsx", "purpose": "成绩趋势折线图(recharts LineChart,归一化分数 0-100)", "deps": ["recharts", "shared/components/ui/chart"] }, { "name": "ClassComparisonChart", "file": "components/class-comparison-chart.tsx", "purpose": "班级对比柱状图(recharts BarChart,均分/及格率/优秀率)", "deps": ["recharts", "shared/components/ui/chart"] }, { "name": "SubjectComparisonChart", "file": "components/subject-comparison-chart.tsx", "purpose": "科目对比雷达图(recharts RadarChart)", "deps": ["recharts", "shared/components/ui/chart"] }, { "name": "GradeDistributionChart", "file": "components/grade-distribution-chart.tsx", "purpose": "分数分布柱状图(recharts BarChart,彩色区间 90-100/80-89/70-79/60-69/<60)", "deps": ["recharts", "shared/components/ui/chart"] } ] } }, "course-plans": { "path": "src/modules/course-plans", "description": "课程计划管理:创建、编辑、删除课程计划(含周计划条目),管理员可管理全部,教师/学生/年级主任/教务主任可查看", "exports": { "actions": [ { "name": "createCoursePlanAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "创建课程计划", "deps": ["requirePermission", "shared/db", "data-access.createCoursePlan"], "usedBy": ["course-plan-form.tsx"] }, { "name": "updateCoursePlanAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(id: string, prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "更新课程计划", "deps": ["requirePermission", "shared/db", "data-access.updateCoursePlan"], "usedBy": ["course-plan-form.tsx"] }, { "name": "deleteCoursePlanAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(id: string) => Promise>", "purpose": "删除课程计划", "deps": ["requirePermission", "shared/db", "data-access.deleteCoursePlan"], "usedBy": ["course-plan-detail.tsx"] }, { "name": "getCoursePlansAction", "permission": "COURSE_PLAN_READ", "signature": "(params?: GetCoursePlansParams) => Promise>", "purpose": "获取课程计划列表", "deps": ["requirePermission", "data-access.getCoursePlans"], "usedBy": ["待扩展"] }, { "name": "getCoursePlanAction", "permission": "COURSE_PLAN_READ", "signature": "(id: string) => Promise>", "purpose": "获取课程计划详情(含周计划条目)", "deps": ["requirePermission", "data-access.getCoursePlanById"], "usedBy": ["待扩展"] }, { "name": "createCoursePlanItemAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "创建周计划条目", "deps": ["requirePermission", "shared/db", "data-access.createCoursePlanItem"], "usedBy": ["course-plan-item-editor.tsx"] }, { "name": "updateCoursePlanItemAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(id: string, prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "更新周计划条目", "deps": ["requirePermission", "shared/db", "data-access.updateCoursePlanItem"], "usedBy": ["course-plan-item-editor.tsx"] }, { "name": "deleteCoursePlanItemAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(id: string) => Promise>", "purpose": "删除周计划条目", "deps": ["requirePermission", "shared/db", "data-access.deleteCoursePlanItem"], "usedBy": ["course-plan-item-editor.tsx"] }, { "name": "toggleCoursePlanItemCompletedAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(id: string, completed: boolean) => Promise>", "purpose": "切换周计划条目完成状态", "deps": ["requirePermission", "shared/db", "data-access.updateCoursePlanItem"], "usedBy": ["course-plan-detail.tsx"] } ], "dataAccess": [ { "name": "getCoursePlans", "signature": "(params?: GetCoursePlansParams) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlans", "shared.db.schema.classes", "shared.db.schema.subjects", "shared.db.schema.users"], "usedBy": ["admin/course-plans/page.tsx", "teacher/course-plans/page.tsx"] }, { "name": "getCoursePlanById", "signature": "(id: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlans", "shared.db.schema.coursePlanItems", "shared.db.schema.classes", "shared.db.schema.subjects", "shared.db.schema.users"], "usedBy": ["admin/course-plans/[id]/page.tsx", "teacher/course-plans/[id]/page.tsx"] }, { "name": "createCoursePlan", "signature": "(data: CreateCoursePlanInput, createdBy: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlans", "@paralleldrive/cuid2"], "usedBy": ["createCoursePlanAction"] }, { "name": "updateCoursePlan", "signature": "(id: string, data: Partial) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlans"], "usedBy": ["updateCoursePlanAction"] }, { "name": "deleteCoursePlan", "signature": "(id: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlans"], "usedBy": ["deleteCoursePlanAction"] }, { "name": "createCoursePlanItem", "signature": "(data: CreateCoursePlanItemInput) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlanItems", "@paralleldrive/cuid2"], "usedBy": ["createCoursePlanItemAction"] }, { "name": "updateCoursePlanItem", "signature": "(id: string, data: Partial) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlanItems"], "usedBy": ["updateCoursePlanItemAction", "toggleCoursePlanItemCompletedAction"] }, { "name": "deleteCoursePlanItem", "signature": "(id: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlanItems"], "usedBy": ["deleteCoursePlanItemAction"] }, { "name": "reorderCoursePlanItems", "signature": "(planId: string, items: ReorderCoursePlanItemInput[]) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlanItems"], "usedBy": ["待扩展"] }, { "name": "getSubjectOptions", "signature": "() => Promise<{id:string;name:string}[]>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.subjects"], "usedBy": ["admin/course-plans/create/page.tsx", "admin/course-plans/[id]/edit/page.tsx"] } ], "schemas": [ { "name": "CreateCoursePlanSchema", "type": "zod", "file": "schema.ts", "definition": "{ classId, subjectId, teacherId, academicYearId?, semester?, totalHours?, weeklyHours?, startDate?, endDate?, syllabus?, objectives?, status? }", "usedBy": ["createCoursePlanAction"] }, { "name": "UpdateCoursePlanSchema", "type": "zod", "file": "schema.ts", "definition": "{ classId?, subjectId?, teacherId?, academicYearId?, semester?, totalHours?, completedHours?, weeklyHours?, startDate?, endDate?, syllabus?, objectives?, status? }", "usedBy": ["updateCoursePlanAction"] }, { "name": "CreateCoursePlanItemSchema", "type": "zod", "file": "schema.ts", "definition": "{ planId, week, topic, content?, hours?, textbookChapter?, notes? }", "usedBy": ["createCoursePlanItemAction"] }, { "name": "UpdateCoursePlanItemSchema", "type": "zod", "file": "schema.ts", "definition": "{ week?, topic?, content?, hours?, textbookChapter?, notes?, isCompleted?, completedAt? }", "usedBy": ["updateCoursePlanItemAction"] } ], "types": [ { "name": "CoursePlan", "type": "interface", "file": "types.ts", "definition": "{ id, classId, subjectId, teacherId, academicYearId, semester, totalHours, completedHours, weeklyHours, startDate, endDate, syllabus, objectives, status, createdBy, createdAt, updatedAt }", "usedBy": ["course-plans/components", "data-access"] }, { "name": "CoursePlanItem", "type": "interface", "file": "types.ts", "definition": "{ id, planId, week, topic, content, hours, textbookChapter, notes, isCompleted, completedAt, createdAt, updatedAt }", "usedBy": ["course-plans/components", "data-access"] }, { "name": "CoursePlanListItem", "type": "interface", "file": "types.ts", "definition": "= CoursePlan & { className, subjectName, teacherName }", "usedBy": ["列表页", "data-access"] }, { "name": "CoursePlanWithItems", "type": "interface", "file": "types.ts", "definition": "= CoursePlanListItem & { items: CoursePlanItem[] }", "usedBy": ["详情页", "data-access"] }, { "name": "CoursePlanStatus", "type": "type", "file": "types.ts", "definition": "\"planning\" | \"active\" | \"completed\" | \"paused\"", "usedBy": ["data-access", "components"] }, { "name": "CoursePlanSemester", "type": "type", "file": "types.ts", "definition": "\"1\" | \"2\"", "usedBy": ["data-access", "components"] }, { "name": "GetCoursePlansParams", "type": "interface", "file": "types.ts", "definition": "{ classId?, teacherId?, subjectId?, status? }", "usedBy": ["getCoursePlans", "getCoursePlansAction"] }, { "name": "ReorderCoursePlanItemInput", "type": "interface", "file": "types.ts", "definition": "{ id, week }", "usedBy": ["reorderCoursePlanItems"] } ], "components": [ { "name": "CoursePlanProgress", "file": "components/course-plan-progress.tsx", "purpose": "进度条组件(completedHours/totalHours 百分比)" }, { "name": "CoursePlanList", "file": "components/course-plan-list.tsx", "purpose": "课程计划列表(支持状态筛选,URL同步)" }, { "name": "CoursePlanForm", "file": "components/course-plan-form.tsx", "purpose": "创建/编辑表单(班级、科目、教师、学年、学期、状态、课时、日期、大纲、目标)" }, { "name": "CoursePlanItemEditor", "file": "components/course-plan-item-editor.tsx", "purpose": "周计划条目编辑器(Dialog,支持创建/编辑/删除/切换完成)" }, { "name": "CoursePlanDetail", "file": "components/course-plan-detail.tsx", "purpose": "详情视图(计划信息、进度、大纲、目标、周计划表格、删除确认)" } ] } }, "parent": { "path": "src/modules/parent", "description": "家长端仪表盘:聚合家长关联子女的学习数据(课表、作业、成绩、班级),支持多子女切换查看。家长通过 parentStudentRelations 表关联子女,DataScope 解析为 children 类型", "exports": { "dataAccess": [ { "name": "getChildren", "signature": "(parentId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.parentStudentRelations", "react.cache"], "usedBy": ["getParentDashboardData (内部)", "parent/children/[studentId]/page.tsx"] }, { "name": "getChildBasicInfo", "signature": "(studentId: string, relation?: string | null) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.users", "shared.db.schema.grades", "shared.db.schema.classEnrollments", "shared.db.schema.classes", "react.cache"], "usedBy": ["getChildDashboardData (内部)"] }, { "name": "getChildDashboardData", "signature": "(studentId: string, relation?: string | null) => Promise", "file": "data-access.ts", "deps": ["getChildBasicInfo", "classes/data-access.getStudentClasses", "classes/data-access.getStudentSchedule", "homework/data-access.getStudentHomeworkAssignments", "homework/data-access.getStudentDashboardGrades", "grades/data-access.getStudentGradeSummary", "react.cache"], "usedBy": ["parent/children/[studentId]/page.tsx", "getParentDashboardData (内部)"] }, { "name": "getParentDashboardData", "signature": "(parentId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.users", "getChildren", "getChildDashboardData", "react.cache"], "usedBy": ["parent/dashboard/page.tsx"] } ], "types": [ { "name": "ParentChildRelation", "type": "type", "file": "types.ts", "definition": "{ id, parentId, studentId, relation: string | null, createdAt: string }", "usedBy": ["getChildren", "getParentDashboardData"] }, { "name": "ChildBasicInfo", "type": "type", "file": "types.ts", "definition": "{ id, name: string | null, email, image: string | null, gradeName: string | null, className: string | null, classId: string | null, relation: string | null }", "usedBy": ["getChildBasicInfo", "ChildDashboardData.basicInfo"] }, { "name": "ChildScheduleItem", "type": "type", "file": "types.ts", "definition": "{ id, classId, className, course, startTime, endTime, location: string | null }", "usedBy": ["ChildDashboardData.todaySchedule", "child-schedule-card.tsx"] }, { "name": "ChildHomeworkSummary", "type": "type", "file": "types.ts", "definition": "{ pendingCount, submittedCount, gradedCount, overdueCount, recentAssignments: StudentHomeworkAssignmentListItem[] }", "usedBy": ["ChildDashboardData.homeworkSummary", "child-homework-summary.tsx"] }, { "name": "ChildDashboardData", "type": "type", "file": "types.ts", "definition": "{ basicInfo: ChildBasicInfo, enrolledClasses: StudentEnrolledClass[], todaySchedule: ChildScheduleItem[], homeworkSummary: ChildHomeworkSummary, gradeTrend: StudentDashboardGradeProps, gradeSummary: StudentGradeSummary | null }", "usedBy": ["getChildDashboardData", "ParentDashboardData.children", "所有 child-* 组件"] }, { "name": "ParentDashboardData", "type": "type", "file": "types.ts", "definition": "{ parentName: string | null, children: ChildDashboardData[] }", "usedBy": ["getParentDashboardData", "parent-dashboard.tsx"] } ], "components": [ { "name": "ParentDashboard", "file": "components/parent-dashboard.tsx", "purpose": "主容器组件(问候语、子女卡片网格、空状态)" }, { "name": "ChildCard", "file": "components/child-card.tsx", "purpose": "子女卡片(头像、姓名、班级、待完成/逾期/平均分统计,点击跳转详情)" }, { "name": "ChildDetailHeader", "file": "components/child-detail-header.tsx", "purpose": "子女详情页头部(返回按钮、头像、姓名、班级、年级、关系)" }, { "name": "ChildDetailPanel", "file": "components/child-detail-panel.tsx", "purpose": "子女详情面板容器(组合 homework/grade/schedule 三个子组件)" }, { "name": "ChildHomeworkSummary", "file": "components/child-homework-summary.tsx", "purpose": "子女作业概览(pending/submitted/graded/overdue 统计 + 最近作业列表)" }, { "name": "ChildGradeSummary", "file": "components/child-grade-summary.tsx", "purpose": "子女成绩概览(Recharts 折线图趋势 + 最新分数 + 班级排名 + 最近成绩列表,use client)" }, { "name": "ChildScheduleCard", "file": "components/child-schedule-card.tsx", "purpose": "子女今日课表卡片(课程、时间、地点、班级)" } ] } }, "messaging": { "path": "src/modules/messaging", "description": "站内消息系统:用户间私信收发(支持回复链)、站内通知(多态类型:message/announcement/homework/grade),SiteHeader 通知下拉菜单展示未读数", "exports": { "actions": [ { "name": "sendMessageAction", "permission": "MESSAGE_SEND", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "发送消息(同时为收件人创建通知;支持 parentMessageId 回复)", "deps": ["requirePermission", "shared/db", "data-access.createMessage", "data-access.createNotification", "revalidatePath"], "usedBy": ["message-compose.tsx"] }, { "name": "markMessageAsReadAction", "permission": "MESSAGE_READ", "signature": "(id: string) => Promise>", "purpose": "标记消息已读(设置 readAt)", "deps": ["requirePermission", "data-access.markMessageAsRead", "revalidatePath"], "usedBy": ["message-detail.tsx", "messages/[id]/page.tsx"] }, { "name": "deleteMessageAction", "permission": "MESSAGE_DELETE", "signature": "(id: string) => Promise>", "purpose": "删除消息(仅发送者或接收者可删)", "deps": ["requirePermission", "data-access.deleteMessage", "revalidatePath"], "usedBy": ["message-detail.tsx"] }, { "name": "getMessagesAction", "permission": "MESSAGE_READ", "signature": "(params?: { type?, page?, pageSize? }) => Promise>>", "purpose": "获取消息列表(收件箱/已发送,分页)", "deps": ["requirePermission", "data-access.getMessages"], "usedBy": ["message-list.tsx"] }, { "name": "getMessageDetailAction", "permission": "MESSAGE_READ", "signature": "(id: string) => Promise>", "purpose": "获取消息详情(含回复线程)", "deps": ["requirePermission", "data-access.getMessageById", "data-access.getMessageThread"], "usedBy": ["message-detail.tsx"] }, { "name": "getRecipientsAction", "permission": "MESSAGE_SEND", "signature": "() => Promise>", "purpose": "获取可发送对象列表(按 DataScope 过滤)", "deps": ["requirePermission", "data-access.getRecipients"], "usedBy": ["messages/compose/page.tsx"] }, { "name": "getNotificationsAction", "permission": "requireAuth", "signature": "(params?: { page?, pageSize? }) => Promise>>", "purpose": "获取当前用户通知列表(分页)", "deps": ["requireAuth", "data-access.getNotifications"], "usedBy": ["notification-dropdown.tsx", "notification-list.tsx"] }, { "name": "markNotificationAsReadAction", "permission": "requireAuth", "signature": "(id: string) => Promise>", "purpose": "标记单条通知已读", "deps": ["requireAuth", "data-access.markNotificationAsRead", "revalidatePath"], "usedBy": ["notification-dropdown.tsx", "notification-list.tsx"] }, { "name": "markAllNotificationsAsReadAction", "permission": "requireAuth", "signature": "() => Promise>", "purpose": "标记所有通知已读", "deps": ["requireAuth", "data-access.markAllNotificationsAsRead", "revalidatePath"], "usedBy": ["notification-dropdown.tsx", "notification-list.tsx"] }, { "name": "getNotificationPreferencesAction", "permission": "requireAuth", "signature": "() => Promise>", "purpose": "获取当前用户的通知偏好设置(首次访问自动创建默认记录)", "deps": ["requireAuth", "notification-preferences.getNotificationPreferences"], "usedBy": ["settings/page.tsx", "settings/components/notification-preferences-form.tsx"] }, { "name": "updateNotificationPreferencesAction", "permission": "requireAuth", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "更新当前用户的通知偏好设置(upsert 语义,未提供字段保留原值)", "deps": ["requireAuth", "notification-preferences.upsertNotificationPreferences", "revalidatePath"], "usedBy": ["settings/components/notification-preferences-form.tsx"] } ], "dataAccess": [ { "name": "getMessages", "signature": "(userId: string, params?: { type?, page?, pageSize? }) => Promise>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages", "shared.db.schema.users"], "usedBy": ["getMessagesAction"] }, { "name": "getMessageById", "signature": "(id: string, userId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages", "shared.db.schema.users"], "usedBy": ["getMessageDetailAction", "messages/[id]/page.tsx"] }, { "name": "getMessageThread", "signature": "(rootId: string, userId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages", "shared.db.schema.users"], "usedBy": ["getMessageDetailAction"] }, { "name": "createMessage", "signature": "(input: CreateMessageInput) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages", "@paralleldrive/cuid2"], "usedBy": ["sendMessageAction"] }, { "name": "markMessageAsRead", "signature": "(id: string, userId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages"], "usedBy": ["markMessageAsReadAction", "messages/[id]/page.tsx"] }, { "name": "deleteMessage", "signature": "(id: string, userId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages"], "usedBy": ["deleteMessageAction"] }, { "name": "getUnreadMessageCount", "signature": "(userId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages"], "usedBy": ["待扩展"] }, { "name": "getNotifications", "signature": "(userId: string, params?: { page?, pageSize? }) => Promise>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messageNotifications"], "usedBy": ["getNotificationsAction"] }, { "name": "createNotification", "signature": "(input: CreateNotificationInput) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messageNotifications", "@paralleldrive/cuid2"], "usedBy": ["sendMessageAction (内部调用)"] }, { "name": "markNotificationAsRead", "signature": "(id: string, userId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messageNotifications"], "usedBy": ["markNotificationAsReadAction"] }, { "name": "markAllNotificationsAsRead", "signature": "(userId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messageNotifications"], "usedBy": ["markAllNotificationsAsReadAction"] }, { "name": "getUnreadNotificationCount", "signature": "(userId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messageNotifications"], "usedBy": ["待扩展"] }, { "name": "getRecipients", "signature": "(ctx: AuthContext) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.users", "shared.db.schema.classEnrollments", "shared.db.schema.classes", "shared.db.schema.grades"], "usedBy": ["getRecipientsAction", "messages/compose/page.tsx"] } ], "notificationPreferences": [ { "name": "getNotificationPreferences", "signature": "(userId: string) => Promise", "file": "notification-preferences.ts", "purpose": "获取用户通知偏好(React cache 包装;若不存在则自动创建默认记录,并发冲突回退到查询)", "deps": ["shared.db", "shared.db.schema.notificationPreferences", "react.cache", "@paralleldrive/cuid2"], "usedBy": ["getNotificationPreferencesAction", "settings/page.tsx"] }, { "name": "upsertNotificationPreferences", "signature": "(userId: string, input: UpdateNotificationPreferencesInput) => Promise", "file": "notification-preferences.ts", "purpose": "更新或插入用户通知偏好(存在则部分更新,不存在则插入;未提供字段保留原值)", "deps": ["shared.db", "shared.db.schema.notificationPreferences", "@paralleldrive/cuid2"], "usedBy": ["updateNotificationPreferencesAction"] } ], "schemas": [ { "name": "SendMessageSchema", "type": "zod", "file": "schema.ts", "definition": "{ receiverId: string, subject?: string, content: string, parentMessageId?: string }", "usedBy": ["sendMessageAction"] } ], "types": [ { "name": "Message", "type": "type", "file": "types.ts", "definition": "{ id, senderId, receiverId, subject: string | null, content, isRead, readAt: string | null, parentMessageId: string | null, createdAt, senderName, receiverName }", "usedBy": ["messaging/components", "页面"] }, { "name": "MessageListItem", "type": "type", "file": "types.ts", "definition": "消息列表项类型(同 Message 精简版)", "usedBy": ["列表页"] }, { "name": "MessageThread", "type": "type", "file": "types.ts", "definition": "{ root: Message, replies: Message[] }", "usedBy": ["详情页"] }, { "name": "Notification", "type": "type", "file": "types.ts", "definition": "{ id, userId, type: NotificationType, title, content: string | null, link: string | null, isRead, createdAt }", "usedBy": ["notification-dropdown", "notification-list"] }, { "name": "NotificationListItem", "type": "type", "file": "types.ts", "definition": "通知列表项类型(同 Notification)", "usedBy": ["列表页"] }, { "name": "NotificationType", "type": "type", "file": "types.ts", "definition": "'message' | 'announcement' | 'homework' | 'grade'", "usedBy": ["data-access", "components"] }, { "name": "MessageType", "type": "type", "file": "types.ts", "definition": "'inbox' | 'sent'", "usedBy": ["getMessages 参数"] }, { "name": "CreateMessageInput", "type": "type", "file": "types.ts", "definition": "{ senderId, receiverId, subject?, content, parentMessageId? }", "usedBy": ["createMessage"] }, { "name": "CreateNotificationInput", "type": "type", "file": "types.ts", "definition": "{ userId, type: NotificationType, title, content?, link? }", "usedBy": ["createNotification"] }, { "name": "RecipientOption", "type": "type", "file": "types.ts", "definition": "{ id: string, name: string }", "usedBy": ["compose 页面下拉选项"] }, { "name": "PaginatedResult", "type": "type", "file": "types.ts", "definition": "{ items: T[], total: number, page: number, pageSize: number, totalPages: number }", "usedBy": ["getMessages", "getNotifications"] }, { "name": "NotificationPreferences", "type": "interface", "file": "types.ts", "definition": "{ id, userId, emailEnabled, smsEnabled, pushEnabled, homeworkNotifications, gradeNotifications, announcementNotifications, messageNotifications, attendanceNotifications, createdAt, updatedAt }", "usedBy": ["notification-preferences", "getNotificationPreferencesAction", "updateNotificationPreferencesAction", "settings/components/notification-preferences-form"] }, { "name": "UpdateNotificationPreferencesInput", "type": "interface", "file": "types.ts", "definition": "{ emailEnabled?, smsEnabled?, pushEnabled?, homeworkNotifications?, gradeNotifications?, announcementNotifications?, messageNotifications?, attendanceNotifications? }", "usedBy": ["upsertNotificationPreferences", "updateNotificationPreferencesAction"] } ], "components": [ { "name": "MessageList", "file": "components/message-list.tsx", "purpose": "消息列表(收件箱/已发送 Tab 切换,已读/未读标记,usePermission 控制写消息按钮)" }, { "name": "MessageDetail", "file": "components/message-detail.tsx", "purpose": "消息详情(含回复线程、回复/删除操作,AlertDialog 删除确认,usePermission 控制按钮可见性)" }, { "name": "MessageCompose", "file": "components/message-compose.tsx", "purpose": "写消息表单(收件人 Select、主题 Input、内容 Textarea,支持回复模式)" }, { "name": "NotificationDropdown", "file": "components/notification-dropdown.tsx", "purpose": "SiteHeader 通知下拉菜单(Bell 图标 + 未读数 Badge,滚动列表,标记已读,查看全部链接)" }, { "name": "NotificationList", "file": "components/notification-list.tsx", "purpose": "通知完整列表(全部标记已读、单条标记已读、查看链接)" } ] } }, "attendance": { "path": "src/modules/attendance", "description": "学生考勤管理:教师按班级/日期点名(单条/批量)、查询考勤记录、统计出勤率/迟到率,学生/家长查看本人/子女考勤汇总,管理员查看全校考勤记录。支持班级考勤规则配置。", "exports": { "actions": [ { "name": "recordAttendanceAction", "permission": "ATTENDANCE_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "创建单条考勤记录", "deps": ["requirePermission", "data-access.createAttendanceRecord", "revalidatePath"], "usedBy": ["attendance-record-list.tsx"] }, { "name": "batchRecordAttendanceAction", "permission": "ATTENDANCE_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "批量点名(班级+日期,表格形式录入每个学生状态)", "deps": ["requirePermission", "data-access.batchCreateAttendanceRecords", "revalidatePath"], "usedBy": ["attendance-sheet.tsx"] }, { "name": "updateAttendanceAction", "permission": "ATTENDANCE_MANAGE", "signature": "(id: string, prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "更新考勤记录(状态、备注)", "deps": ["requirePermission", "data-access.updateAttendanceRecord", "revalidatePath"], "usedBy": ["attendance-record-list.tsx"] }, { "name": "deleteAttendanceAction", "permission": "ATTENDANCE_MANAGE", "signature": "(id: string) => Promise>", "purpose": "删除考勤记录", "deps": ["requirePermission", "data-access.deleteAttendanceRecord", "revalidatePath"], "usedBy": ["attendance-record-list.tsx"] }, { "name": "getAttendanceAction", "permission": "ATTENDANCE_READ", "signature": "(params?: AttendanceQueryParams) => Promise>", "purpose": "分页查询考勤记录(按 scope 过滤)", "deps": ["requirePermission", "data-access.getAttendanceRecords"], "usedBy": ["teacher/attendance/page.tsx", "admin/attendance/page.tsx"] }, { "name": "getStudentAttendanceAction", "permission": "ATTENDANCE_READ", "signature": "(studentId: string) => Promise>", "purpose": "获取学生考勤汇总(含 DataScope 二次校验:class_members 仅查自己,children 仅查子女)", "deps": ["requirePermission", "data-access-stats.getStudentAttendanceSummary"], "usedBy": ["student/attendance/page.tsx", "parent/attendance/page.tsx"] }, { "name": "getClassAttendanceStatsAction", "permission": "ATTENDANCE_READ", "signature": "(classId: string, startDate?: string, endDate?: string) => Promise>", "purpose": "获取班级考勤统计", "deps": ["requirePermission", "data-access-stats.getClassAttendanceStats"], "usedBy": ["teacher/attendance/stats/page.tsx"] }, { "name": "getClassAttendanceForDateAction", "permission": "ATTENDANCE_READ", "signature": "(classId: string, date: string) => Promise>", "purpose": "获取班级指定日期考勤(用于点名页加载已有记录)", "deps": ["requirePermission", "data-access.getClassAttendanceForDate"], "usedBy": ["attendance-sheet.tsx"] }, { "name": "saveAttendanceRulesAction", "permission": "ATTENDANCE_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "保存班级考勤规则(upsert)", "deps": ["requirePermission", "data-access.upsertAttendanceRules", "revalidatePath"], "usedBy": ["attendance-rules-form.tsx"] }, { "name": "getAttendanceRulesAction", "permission": "ATTENDANCE_READ", "signature": "(classId?: string) => Promise>", "purpose": "获取班级考勤规则", "deps": ["requirePermission", "data-access.getAttendanceRules"], "usedBy": ["attendance-rules-form.tsx"] } ], "dataAccess": [ { "name": "getAttendanceRecords", "signature": "(params: AttendanceQueryParams & { scope: DataScope; currentUserId?: string }) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords", "shared.db.schema.users", "shared.db.schema.classes", "types.DataScope"], "usedBy": ["getAttendanceAction"] }, { "name": "getClassAttendanceForDate", "signature": "(classId: string, date: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords", "shared.db.schema.users", "shared.db.schema.classes"], "usedBy": ["getClassAttendanceForDateAction"] }, { "name": "createAttendanceRecord", "signature": "(data: RecordAttendanceInput, recordedBy: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords", "@paralleldrive/cuid2"], "usedBy": ["recordAttendanceAction"] }, { "name": "batchCreateAttendanceRecords", "signature": "(data: BatchRecordAttendanceInput, recordedBy: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords", "@paralleldrive/cuid2"], "usedBy": ["batchRecordAttendanceAction"] }, { "name": "updateAttendanceRecord", "signature": "(id: string, data: UpdateAttendanceInput) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords"], "usedBy": ["updateAttendanceAction"] }, { "name": "deleteAttendanceRecord", "signature": "(id: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords"], "usedBy": ["deleteAttendanceAction"] }, { "name": "getClassStudentsForAttendance", "signature": "(classId: string) => Promise>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.classEnrollments", "shared.db.schema.users"], "usedBy": ["attendance-sheet.tsx"] }, { "name": "getAttendanceRules", "signature": "(classId?: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRules"], "usedBy": ["getAttendanceRulesAction"] }, { "name": "upsertAttendanceRules", "signature": "(data: AttendanceRuleInput) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRules", "@paralleldrive/cuid2"], "usedBy": ["saveAttendanceRulesAction"] }, { "name": "getStudentAttendanceSummary", "signature": "(studentId: string, startDate?: string, endDate?: string) => Promise", "file": "data-access-stats.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords", "shared.db.schema.classes", "shared.db.schema.users"], "usedBy": ["getStudentAttendanceAction", "student/attendance/page.tsx", "parent/attendance/page.tsx"] }, { "name": "getClassAttendanceStats", "signature": "(classId: string, startDate?: string, endDate?: string) => Promise", "file": "data-access-stats.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords", "shared.db.schema.classes", "shared.db.schema.users"], "usedBy": ["getClassAttendanceStatsAction", "teacher/attendance/stats/page.tsx"] } ], "schemas": [ { "name": "AttendanceStatusEnum", "type": "zod", "file": "schema.ts", "definition": "enum('present','absent','late','early_leave','excused')", "usedBy": ["RecordAttendanceSchema", "BatchRecordAttendanceSchema", "UpdateAttendanceSchema"] }, { "name": "RecordAttendanceSchema", "type": "zod", "file": "schema.ts", "definition": "{ studentId, classId, scheduleId?, date, status, remark? }", "usedBy": ["recordAttendanceAction"] }, { "name": "BatchRecordAttendanceSchema", "type": "zod", "file": "schema.ts", "definition": "{ records: [{ studentId, classId, scheduleId?, date, status, remark? }] }", "usedBy": ["batchRecordAttendanceAction"] }, { "name": "UpdateAttendanceSchema", "type": "zod", "file": "schema.ts", "definition": "{ status?, remark?, scheduleId? }", "usedBy": ["updateAttendanceAction"] }, { "name": "AttendanceRuleSchema", "type": "zod", "file": "schema.ts", "definition": "{ classId, lateThresholdMinutes?, earlyLeaveThresholdMinutes?, enableAutoMark? }", "usedBy": ["saveAttendanceRulesAction"] } ], "types": [ { "name": "AttendanceStatus", "type": "type", "file": "types.ts", "definition": "'present' | 'absent' | 'late' | 'early_leave' | 'excused'", "usedBy": ["attendance/data-access", "attendance/components"] }, { "name": "AttendanceRecord", "type": "type", "file": "types.ts", "definition": "考勤记录完整类型", "usedBy": ["attendance/data-access"] }, { "name": "AttendanceListItem", "type": "type", "file": "types.ts", "definition": "{ id, studentId, studentName, classId, className, scheduleId, date, status, remark, recordedBy, recorderName, createdAt }", "usedBy": ["attendance/components", "页面"] }, { "name": "AttendanceStats", "type": "type", "file": "types.ts", "definition": "{ total, present, absent, late, earlyLeave, excused, presentRate, lateRate }", "usedBy": ["attendance-stats-card.tsx"] }, { "name": "StudentAttendanceSummary", "type": "type", "file": "types.ts", "definition": "{ studentId, studentName, stats: AttendanceStats, recentRecords: AttendanceListItem[] }", "usedBy": ["student-attendance-view.tsx"] }, { "name": "ClassAttendanceSummary", "type": "type", "file": "types.ts", "definition": "{ classId, className, date, stats: AttendanceStats, studentRecords: AttendanceListItem[] }", "usedBy": ["teacher/attendance/stats"] }, { "name": "AttendanceRule", "type": "type", "file": "types.ts", "definition": "{ id, classId, lateThresholdMinutes, earlyLeaveThresholdMinutes, enableAutoMark, createdAt, updatedAt }", "usedBy": ["attendance-rules-form.tsx"] }, { "name": "AttendanceQueryParams", "type": "type", "file": "types.ts", "definition": "{ classId?, studentId?, date?, startDate?, endDate?, status?, page?, pageSize? }", "usedBy": ["getAttendanceRecords", "getAttendanceAction"] }, { "name": "PaginatedAttendanceResult", "type": "type", "file": "types.ts", "definition": "{ items: AttendanceListItem[], total, page, pageSize, totalPages }", "usedBy": ["getAttendanceRecords", "getAttendanceAction"] }, { "name": "ATTENDANCE_STATUS_LABELS", "type": "const", "file": "types.ts", "definition": "状态中文标签常量", "usedBy": ["attendance/components"] }, { "name": "ATTENDANCE_STATUS_COLORS", "type": "const", "file": "types.ts", "definition": "状态颜色常量(用于 Badge)", "usedBy": ["attendance/components"] } ], "components": [ { "name": "AttendanceSheet", "file": "components/attendance-sheet.tsx", "purpose": "批量点名表单(班级/日期选择器 + 学生表格 + 每行状态 Select + 全部标记到场按钮)" }, { "name": "AttendanceRecordList", "file": "components/attendance-record-list.tsx", "purpose": "考勤记录列表表格(含删除确认对话框)" }, { "name": "AttendanceStatsCard", "file": "components/attendance-stats-card.tsx", "purpose": "统计卡片(总数、到场、缺勤、迟到、早退、请假、出勤率、迟到率)" }, { "name": "AttendanceFilters", "file": "components/attendance-filters.tsx", "purpose": "URL 同步筛选器(班级、状态、日期)" }, { "name": "StudentAttendanceView", "file": "components/student-attendance-view.tsx", "purpose": "学生/家长视图(统计卡片 + 最近记录表格)" }, { "name": "AttendanceRulesForm", "file": "components/attendance-rules-form.tsx", "purpose": "考勤规则配置表单(班级选择器、迟到/早退阈值、自动标记勾选)" } ] } }, "scheduling": { "path": "src/modules/scheduling", "description": "排课与调课:管理员配置班级排课规则(每日课时、连续课时、午休、上下学时间、避免背靠背、科目均衡),自动排课引擎按规则生成周课表,调课/代课申请与审批流程,课表冲突检测。", "exports": { "actions": [ { "name": "saveSchedulingRulesAction", "permission": "SCHEDULE_ADJUST", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "保存班级排课规则(upsert,classId 为空时为全局规则)", "deps": ["requirePermission", "data-access.upsertSchedulingRules", "revalidatePath"], "usedBy": ["scheduling-rules-form.tsx"] }, { "name": "autoScheduleAction", "permission": "SCHEDULE_AUTO", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "根据规则与科目分配生成预览课表(不落库)", "deps": ["requirePermission", "data-access.getSchedulingRules", "data-access.getClassSubjectsForScheduling", "data-access.getClassroomsForScheduling", "auto-scheduler.autoSchedule", "auto-scheduler.buildDefaultTimeSlots", "revalidatePath"], "usedBy": ["auto-schedule-panel.tsx"] }, { "name": "applyAutoScheduleAction", "permission": "SCHEDULE_AUTO", "signature": "(classId: string, schedules: Array<{ weekday, startTime, endTime, course, location }>) => Promise>", "purpose": "将生成的课表写入 classSchedule 表(先删除该班旧课表再插入新课表,事务)", "deps": ["requirePermission", "shared.db", "shared.db.schema.classSchedule", "@paralleldrive/cuid2", "revalidatePath"], "usedBy": ["auto-schedule-panel.tsx"] }, { "name": "requestScheduleChangeAction", "permission": "SCHEDULE_ADJUST", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "提交调课/代课申请(status=pending)", "deps": ["requirePermission", "data-access.createScheduleChange", "revalidatePath"], "usedBy": ["schedule-change-form.tsx"] }, { "name": "approveScheduleChangeAction", "permission": "SCHEDULE_AUTO", "signature": "(changeId: string) => Promise", "purpose": "审批通过调课申请(status=approved)", "deps": ["requirePermission", "data-access.updateScheduleChangeStatus", "revalidatePath"], "usedBy": ["schedule-change-list.tsx"] }, { "name": "rejectScheduleChangeAction", "permission": "SCHEDULE_AUTO", "signature": "(changeId: string, reason?: string) => Promise", "purpose": "驳回调课申请(status=rejected)", "deps": ["requirePermission", "data-access.updateScheduleChangeStatus", "revalidatePath"], "usedBy": ["schedule-change-list.tsx"] }, { "name": "getScheduleChangesAction", "permission": "SCHEDULE_ADJUST", "signature": "(params: ScheduleChangeQueryParams) => Promise>", "purpose": "查询调课申请列表(可按 classId/status/requesterId 过滤)", "deps": ["requirePermission", "data-access.getScheduleChanges"], "usedBy": ["admin/scheduling/changes/page.tsx", "teacher/schedule-changes/page.tsx"] }, { "name": "getClassConflictsAction", "permission": "SCHEDULE_ADJUST", "signature": "(classId: string) => Promise>", "purpose": "检测班级课表时间重叠冲突", "deps": ["requirePermission", "data-access.getClassConflicts"], "usedBy": ["schedule-conflicts-view.tsx"] } ], "dataAccess": [ { "name": "getSchedulingRules", "signature": "(classId?: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.schedulingRules"], "usedBy": ["saveSchedulingRulesAction", "autoScheduleAction", "admin/scheduling/rules/page.tsx"] }, { "name": "upsertSchedulingRules", "signature": "(data: SchedulingRuleInput) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.schedulingRules", "@paralleldrive/cuid2"], "usedBy": ["saveSchedulingRulesAction"] }, { "name": "getScheduleChanges", "signature": "(params: ScheduleChangeQueryParams) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.scheduleChanges", "shared.db.schema.classes", "shared.db.schema.users"], "usedBy": ["getScheduleChangesAction", "admin/scheduling/changes/page.tsx", "teacher/schedule-changes/page.tsx"] }, { "name": "createScheduleChange", "signature": "(data: ScheduleChangeInput, requestedBy: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.scheduleChanges", "@paralleldrive/cuid2"], "usedBy": ["requestScheduleChangeAction"] }, { "name": "updateScheduleChangeStatus", "signature": "(id: string, status: 'approved'|'rejected'|'completed', approverId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.scheduleChanges"], "usedBy": ["approveScheduleChangeAction", "rejectScheduleChangeAction"] }, { "name": "getClassConflicts", "signature": "(classId: string) => Promise", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.classSchedule"], "usedBy": ["getClassConflictsAction"] }, { "name": "getAdminClassesForScheduling", "signature": "() => Promise>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.classes"], "usedBy": ["admin/scheduling/rules/page.tsx", "admin/scheduling/auto/page.tsx", "admin/scheduling/changes/page.tsx", "teacher/schedule-changes/page.tsx"] }, { "name": "getTeachersForScheduling", "signature": "() => Promise>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.users", "shared.db.schema.classSubjectTeachers"], "usedBy": ["teacher/schedule-changes/page.tsx"] }, { "name": "getClassroomsForScheduling", "signature": "() => Promise>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.classrooms"], "usedBy": ["autoScheduleAction"] }, { "name": "getClassSubjectsForScheduling", "signature": "(classId: string) => Promise>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.classSubjectTeachers", "shared.db.schema.subjects"], "usedBy": ["autoScheduleAction"] } ], "autoScheduler": [ { "name": "autoSchedule", "signature": "(params: AutoScheduleParams) => AutoScheduleResult", "file": "auto-scheduler.ts", "purpose": "贪心+冲突检测排课算法:按科目每周课时降序,为每节课选择第一个满足约束的时段(午休、每日窗口、班级/教师/教室冲突、每日最大课时、避免背靠背)", "deps": ["findOptimalSlot", "validateSchedule"], "usedBy": ["autoScheduleAction"] }, { "name": "findOptimalSlot", "signature": "(args) => TimeSlot | null", "file": "auto-scheduler.ts", "purpose": "在候选时段中找到第一个满足所有约束的时段", "usedBy": ["autoSchedule"] }, { "name": "validateSchedule", "signature": "(schedules: GeneratedSchedule[], rules: SchedulingRule) => ScheduleConflict[]", "file": "auto-scheduler.ts", "purpose": "校验生成的课表是否违反规则,返回冲突列表", "usedBy": ["autoSchedule"] }, { "name": "buildDefaultTimeSlots", "signature": "(morningStart, afternoonEnd, lunchBreakStart, lunchBreakEnd) => TimeSlot[]", "file": "auto-scheduler.ts", "purpose": "根据上下学时间和午休时间构建默认时段(周一至周五,上午4节+下午4节)", "usedBy": ["autoScheduleAction"] } ], "schemas": [ { "name": "SchedulingRuleSchema", "type": "zod", "file": "schema.ts", "definition": "{ classId, maxDailyHours?, maxContinuousHours?, lunchBreakStart?, lunchBreakEnd?, morningStart?, afternoonEnd?, avoidBackToBack?, balancedSubjects? }", "usedBy": ["saveSchedulingRulesAction"] }, { "name": "ScheduleChangeSchema", "type": "zod", "file": "schema.ts", "definition": "{ classId, originalScheduleId?, originalTeacherId?, substituteTeacherId?, originalDate?, newDate?, newStartTime?, newEndTime?, reason }", "usedBy": ["requestScheduleChangeAction"] }, { "name": "AutoScheduleParamsSchema", "type": "zod", "file": "schema.ts", "definition": "{ classId, rules: SchedulingRuleSchema, subjects: [{ subjectId, subjectName, weeklyHours, teacherId? }], teachers: [{ id, name }], classrooms: [{ id, name }], timeSlots: [{ weekday, startTime, endTime }] }", "usedBy": ["autoScheduleAction"] }, { "name": "ScheduleChangeStatusEnum", "type": "zod", "file": "schema.ts", "definition": "enum('pending','approved','rejected','completed')", "usedBy": ["ScheduleChangeSchema"] }, { "name": "ApproveScheduleChangeSchema", "type": "zod", "file": "schema.ts", "definition": "{ changeId, reason? }", "usedBy": ["approveScheduleChangeAction"] } ], "types": [ { "name": "ScheduleChangeStatus", "type": "type", "file": "types.ts", "definition": "'pending' | 'approved' | 'rejected' | 'completed'", "usedBy": ["scheduling/data-access", "scheduling/components"] }, { "name": "SchedulingRule", "type": "type", "file": "types.ts", "definition": "{ id, classId, maxDailyHours, maxContinuousHours, lunchBreakStart, lunchBreakEnd, morningStart, afternoonEnd, avoidBackToBack, balancedSubjects, createdAt, updatedAt }", "usedBy": ["scheduling-rules-form.tsx", "auto-scheduler.ts"] }, { "name": "ScheduleChange", "type": "type", "file": "types.ts", "definition": "调课申请完整类型", "usedBy": ["scheduling/data-access"] }, { "name": "ScheduleChangeListItem", "type": "type", "file": "types.ts", "definition": "{ ...ScheduleChange, className, originalTeacherName, substituteTeacherName, requesterName, approverName }", "usedBy": ["schedule-change-list.tsx", "页面"] }, { "name": "TimeSlot", "type": "type", "file": "types.ts", "definition": "{ weekday, startTime, endTime }", "usedBy": ["auto-scheduler.ts"] }, { "name": "ScheduleConflict", "type": "type", "file": "types.ts", "definition": "{ type: 'teacher_overlap'|'classroom_overlap'|'class_overlap'|'rule_violation', description, scheduleIds }", "usedBy": ["auto-schedule-result.tsx", "schedule-conflicts-view.tsx"] }, { "name": "AutoScheduleResult", "type": "type", "file": "types.ts", "definition": "{ success, scheduledCount, conflictCount, conflicts, schedules: GeneratedSchedule[] }", "usedBy": ["auto-schedule-panel.tsx", "auto-schedule-result.tsx"] }, { "name": "GeneratedSchedule", "type": "type", "file": "types.ts", "definition": "{ classId, weekday, startTime, endTime, course, location, teacherId, subjectId }", "usedBy": ["auto-scheduler.ts", "auto-schedule-result.tsx"] }, { "name": "AutoScheduleParams", "type": "type", "file": "types.ts", "definition": "{ classId, rules, subjects, teachers, classrooms, timeSlots }", "usedBy": ["auto-scheduler.ts", "autoScheduleAction"] }, { "name": "ScheduleChangeQueryParams", "type": "type", "file": "types.ts", "definition": "{ classId?, status?, requesterId? }", "usedBy": ["getScheduleChanges", "getScheduleChangesAction"] }, { "name": "SCHEDULE_CHANGE_STATUS_LABELS", "type": "const", "file": "types.ts", "definition": "状态英文标签常量", "usedBy": ["schedule-change-list.tsx"] }, { "name": "SCHEDULE_CHANGE_STATUS_COLORS", "type": "const", "file": "types.ts", "definition": "状态颜色常量(用于 Badge)", "usedBy": ["schedule-change-list.tsx"] } ], "components": [ { "name": "SchedulingRulesForm", "file": "components/scheduling-rules-form.tsx", "purpose": "排课规则配置表单(班级选择器、每日最大课时、连续课时、午休时间、上下学时间、避免背靠背、科目均衡)" }, { "name": "AutoSchedulePanel", "file": "components/auto-schedule-panel.tsx", "purpose": "自动排课面板(班级选择→预览→应用流程,调用 autoScheduleAction 和 applyAutoScheduleAction)" }, { "name": "AutoScheduleResultView", "file": "components/auto-schedule-result.tsx", "purpose": "排课结果预览(课表表格 + 冲突/警告列表)" }, { "name": "ScheduleChangeForm", "file": "components/schedule-change-form.tsx", "purpose": "调课/代课申请表单(班级、原任课教师、代课教师、原日期、新日期、新时间、原因)" }, { "name": "ScheduleChangeList", "file": "components/schedule-change-list.tsx", "purpose": "调课申请列表表格(含审批/驳回对话框,canApprove 控制是否显示审批按钮)" }, { "name": "ScheduleConflictsView", "file": "components/schedule-conflicts-view.tsx", "purpose": "冲突检测视图(班级选择器 + 检测按钮 + 冲突结果列表)" } ] } }, "proctoring": { "path": "src/modules/proctoring", "description": "考试监考模块:监考模式考试实时监控、防作弊事件采集、教师监考面板、学生端防作弊监控、考试模式配置", "exports": { "actions": [ {"name": "recordProctoringEventAction", "permission": "requireAuth()", "signature": "(prevState: ActionState<{id:string}> | null, formData: FormData) => Promise>", "purpose": "学生端上报监考事件(含 submission 归属校验)", "deps": ["requireAuth", "shared/db", "data-access.recordProctoringEvent"], "usedBy": ["anti-cheat-monitor.tsx"]}, {"name": "getProctoringDashboardAction", "permission": "EXAM_PROCTOR", "signature": "(examId: string) => Promise>", "purpose": "获取监考面板数据(摘要+学生状态+最近事件)", "deps": ["requirePermission(EXAM_PROCTOR)", "data-access.getExamForProctoring,getExamProctoringSummary,getStudentProctoringStatuses,getRecentProctoringEvents"], "usedBy": ["proctoring-dashboard.tsx"]} ], "dataAccess": [ {"name": "recordProctoringEvent", "signature": "(input: RecordProctoringEventInput) => Promise", "purpose": "记录一条监考事件", "usedBy": ["actions.recordProctoringEventAction", "api/proctoring/event/route.ts"]}, {"name": "getProctoringEvents", "signature": "(examId: string, filters?: GetProctoringEventsFilters) => Promise", "purpose": "查询考试监考事件(含学生姓名、考试标题)", "usedBy": ["待扩展"]}, {"name": "getProctoringEventsBySubmission", "signature": "(submissionId: string) => Promise", "purpose": "查询提交的监考事件", "usedBy": ["待扩展"]}, {"name": "getExamProctoringSummary", "signature": "(examId: string) => Promise", "purpose": "获取考试监考摘要", "usedBy": ["actions.getProctoringDashboardAction", "teacher/exams/[id]/proctoring/page.tsx"]}, {"name": "getStudentProctoringStatuses", "signature": "(examId: string) => Promise", "purpose": "获取所有学生监考状态", "usedBy": ["actions.getProctoringDashboardAction", "teacher/exams/[id]/proctoring/page.tsx"]}, {"name": "getExamForProctoring", "signature": "(examId: string) => Promise<{id,title,examMode,config} | null>", "purpose": "获取考试信息(含 examMode 设置)", "usedBy": ["actions.getProctoringDashboardAction", "teacher/exams/[id]/proctoring/page.tsx"]}, {"name": "getRecentProctoringEvents", "signature": "(examId: string, limit?: number) => Promise", "purpose": "获取最近 N 条监考事件", "usedBy": ["actions.getProctoringDashboardAction", "teacher/exams/[id]/proctoring/page.tsx"]} ], "types": [ {"name": "ProctoringEventType", "type": "type", "definition": "\"tab_switch\" | \"window_blur\" | \"copy_attempt\" | \"paste_attempt\" | \"right_click\" | \"devtools_open\" | \"fullscreen_exit\" | \"idle_timeout\""}, {"name": "ExamMode", "type": "type", "definition": "\"homework\" | \"timed\" | \"proctored\""}, {"name": "ProctoringEvent", "type": "interface", "definition": "{ id, submissionId, studentId, examId, eventType, eventDetail?, occurredAt, createdAt }"}, {"name": "ProctoringEventWithDetails", "type": "interface", "definition": "ProctoringEvent & { studentName, examTitle }"}, {"name": "ExamProctoringSummary", "type": "interface", "definition": "{ examId, examTitle, examMode, totalStudents, startedStudents, submittedStudents, totalEvents, abnormalStudents, eventsByType }"}, {"name": "StudentProctoringStatus", "type": "interface", "definition": "{ studentId, studentName, submissionId, submissionStatus, eventCount, lastEventAt, isAbnormal, eventsByType }"}, {"name": "ProctoringDashboardData", "type": "interface", "definition": "{ summary, students, recentEvents }"}, {"name": "ExamModeConfig", "type": "interface", "definition": "{ examMode, durationMinutes, shuffleQuestions, allowLateStart, lateStartGraceMinutes, antiCheatEnabled }"}, {"name": "PROCTORING_EVENT_LABELS", "type": "const", "description": "事件类型中文标签常量"}, {"name": "EXAM_MODE_LABELS", "type": "const", "description": "考试模式中文标签常量"}, {"name": "ABNORMAL_EVENT_THRESHOLD", "type": "const", "description": "异常学生事件数阈值(3)"} ], "components": [ {"name": "ProctoringDashboard", "file": "components/proctoring-dashboard.tsx", "purpose": "教师监考面板(实时学生状态、异常事件统计、异常学生高亮、10 秒轮询、usePermission 权限控制)"}, {"name": "AntiCheatMonitor", "file": "components/anti-cheat-monitor.tsx", "purpose": "学生端防作弊监控(visibilitychange/blur/copy/paste/contextmenu/keydown/fullscreenchange 监听、空闲超时检测、强制全屏、警告提示、事件上报)"}, {"name": "ExamModeConfig", "file": "components/exam-mode-config.tsx", "purpose": "考试模式配置(react-hook-form Controller,作业/限时/监考模式选择,限时设置时长,监考设置防作弊选项)"} ] } }, "diagnostic": { "path": "src/modules/diagnostic", "description": "学情诊断报告模块:基于知识点掌握度(knowledgePointMastery)生成个人/班级诊断报告,掌握度雷达图(学生 vs 班级平均),强项/弱项分析,知识点掌握度热力图,需重点关注学生列表,报告发布/删除管理", "exports": { "dataAccess": [ { "name": "getStudentMastery", "signature": "(studentId: string) => Promise", "file": "data-access.ts", "purpose": "获取学生在所有知识点的掌握度(含知识点名称,按掌握度降序)", "deps": ["shared.db", "shared.db.schema.knowledgePointMastery", "shared.db.schema.knowledgePoints"], "usedBy": ["data-access.getStudentMasterySummary", "teacher/diagnostic/student/[studentId]/page.tsx"] }, { "name": "getStudentMasterySummary", "signature": "(studentId: string) => Promise", "file": "data-access.ts", "purpose": "获取学生掌握度摘要(平均掌握度、强项≥80%、弱项<60%)", "deps": ["shared.db", "shared.db.schema.users", "data-access.getStudentMastery"], "usedBy": ["data-access-reports.generateDiagnosticReport", "teacher/diagnostic/student/[studentId]/page.tsx", "student/diagnostic/page.tsx"] }, { "name": "updateMasteryFromSubmission", "signature": "(submissionId: string) => Promise", "file": "data-access.ts", "purpose": "从提交答案更新掌握度(按知识点聚合正确率,onDuplicateKeyUpdate upsert)", "deps": ["shared.db", "shared.db.schema.examSubmissions", "shared.db.schema.submissionAnswers", "shared.db.schema.questionsToKnowledgePoints", "shared.db.schema.knowledgePointMastery"], "usedBy": ["待扩展(作业/考试提交后触发)"] }, { "name": "getClassMasterySummary", "signature": "(classId: string) => Promise", "file": "data-access.ts", "purpose": "获取班级掌握度摘要(学生数、平均掌握度、知识点统计、需重点关注学生)", "deps": ["shared.db", "shared.db.schema.classes", "shared.db.schema.classEnrollments", "shared.db.schema.users", "shared.db.schema.knowledgePointMastery", "shared.db.schema.knowledgePoints"], "usedBy": ["data-access-reports.generateClassDiagnosticReport", "teacher/diagnostic/class/[classId]/page.tsx"] }, { "name": "getKnowledgePointStats", "signature": "(classId?: string, gradeId?: string) => Promise", "file": "data-access.ts", "purpose": "获取知识点统计(按班级或年级聚合平均掌握度、掌握人数、未掌握人数)", "deps": ["shared.db", "shared.db.schema.classEnrollments", "shared.db.schema.users", "shared.db.schema.knowledgePointMastery", "shared.db.schema.knowledgePoints"], "usedBy": ["teacher/diagnostic/student/[studentId]/page.tsx (班级平均对比)"] }, { "name": "generateDiagnosticReport", "signature": "(studentId: string, period: string, generatedBy: string) => Promise", "file": "data-access-reports.ts", "purpose": "生成个人诊断报告(计算 overallScore、强项/弱项列表、复习建议,status=draft)", "deps": ["shared.db", "shared.db.schema.learningDiagnosticReports", "data-access.getStudentMasterySummary", "@paralleldrive/cuid2"], "usedBy": ["actions.generateStudentReportAction"] }, { "name": "generateClassDiagnosticReport", "signature": "(classId: string, period: string, generatedBy: string) => Promise", "file": "data-access-reports.ts", "purpose": "生成班级诊断报告(聚合班级掌握度,识别薄弱知识点,status=draft,studentId 存生成者 ID)", "deps": ["shared.db", "shared.db.schema.learningDiagnosticReports", "data-access.getClassMasterySummary", "@paralleldrive/cuid2"], "usedBy": ["actions.generateClassReportAction"] }, { "name": "getDiagnosticReports", "signature": "(filters: DiagnosticReportQueryParams) => Promise", "file": "data-access-reports.ts", "purpose": "查询诊断报告列表(可按 studentId/reportType/status/period 过滤,含学生名和生成者名)", "deps": ["shared.db", "shared.db.schema.learningDiagnosticReports", "shared.db.schema.users"], "usedBy": ["actions.getDiagnosticReportsAction", "teacher/diagnostic/page.tsx", "teacher/diagnostic/student/[studentId]/page.tsx", "student/diagnostic/page.tsx"] }, { "name": "getDiagnosticReportById", "signature": "(id: string) => Promise", "file": "data-access-reports.ts", "purpose": "获取报告详情(含学生名和生成者名)", "deps": ["shared.db", "shared.db.schema.learningDiagnosticReports", "shared.db.schema.users"], "usedBy": ["actions.getDiagnosticReportByIdAction"] }, { "name": "publishDiagnosticReport", "signature": "(id: string) => Promise", "file": "data-access-reports.ts", "purpose": "发布诊断报告(status=published)", "deps": ["shared.db", "shared.db.schema.learningDiagnosticReports"], "usedBy": ["actions.publishReportAction"] }, { "name": "deleteDiagnosticReport", "signature": "(id: string) => Promise", "file": "data-access-reports.ts", "purpose": "删除诊断报告", "deps": ["shared.db", "shared.db.schema.learningDiagnosticReports"], "usedBy": ["actions.deleteReportAction"] } ], "actions": [ { "name": "generateStudentReportAction", "permission": "DIAGNOSTIC_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "生成学生个人诊断报告(formData: studentId, period)", "deps": ["requirePermission", "data-access-reports.generateDiagnosticReport", "revalidatePath"], "usedBy": ["components/student-diagnostic-view.tsx"] }, { "name": "generateClassReportAction", "permission": "DIAGNOSTIC_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "生成班级诊断报告(formData: classId, period)", "deps": ["requirePermission", "data-access-reports.generateClassDiagnosticReport", "revalidatePath"], "usedBy": ["components/class-diagnostic-view.tsx"] }, { "name": "publishReportAction", "permission": "DIAGNOSTIC_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "发布诊断报告(formData: id)", "deps": ["requirePermission", "data-access-reports.publishDiagnosticReport", "revalidatePath"], "usedBy": ["components/report-list.tsx"] }, { "name": "deleteReportAction", "permission": "DIAGNOSTIC_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "删除诊断报告(formData: id)", "deps": ["requirePermission", "data-access-reports.deleteDiagnosticReport", "revalidatePath"], "usedBy": ["components/report-list.tsx"] }, { "name": "getDiagnosticReportsAction", "permission": "DIAGNOSTIC_READ", "signature": "(params: DiagnosticReportQueryParams) => Promise>", "file": "actions.ts", "purpose": "查询诊断报告列表(读权限)", "deps": ["requirePermission", "data-access-reports.getDiagnosticReports"], "usedBy": ["待扩展"] }, { "name": "getDiagnosticReportByIdAction", "permission": "DIAGNOSTIC_READ", "signature": "(id: string) => Promise>", "file": "actions.ts", "purpose": "获取诊断报告详情(读权限)", "deps": ["requirePermission", "data-access-reports.getDiagnosticReportById"], "usedBy": ["待扩展"] } ], "types": [ { "name": "DiagnosticReportType", "type": "type", "file": "types.ts", "definition": "\"individual\" | \"class\" | \"grade\"", "usedBy": ["types.DiagnosticReport.reportType", "actions", "components/report-list.tsx"] }, { "name": "DiagnosticReportStatus", "type": "type", "file": "types.ts", "definition": "\"draft\" | \"published\" | \"archived\"", "usedBy": ["types.DiagnosticReport.status", "actions", "components/report-list.tsx"] }, { "name": "KnowledgePointMastery", "type": "interface", "file": "types.ts", "definition": "{ id, studentId, knowledgePointId, masteryLevel(0-100), totalQuestions, correctQuestions, lastAssessedAt, createdAt, updatedAt }", "usedBy": ["data-access", "types.MasteryWithKnowledgePoint"] }, { "name": "MasteryWithKnowledgePoint", "type": "interface", "file": "types.ts", "definition": "KnowledgePointMastery & { knowledgePointName, knowledgePointDescription }", "usedBy": ["data-access.getStudentMastery", "types.StudentMasterySummary"] }, { "name": "StudentMasterySummary", "type": "interface", "file": "types.ts", "definition": "{ studentId, studentName, averageMastery, totalKnowledgePoints, strengths(≥80), weaknesses(<60), allMastery }", "usedBy": ["data-access.getStudentMasterySummary", "data-access-reports.generateDiagnosticReport", "components/student-diagnostic-view.tsx"] }, { "name": "DiagnosticReport", "type": "interface", "file": "types.ts", "definition": "{ id, studentId, generatedBy, reportType, period, summary, strengths[], weaknesses[], recommendations[], overallScore, status, createdAt, updatedAt }", "usedBy": ["data-access-reports", "types.DiagnosticReportWithDetails"] }, { "name": "DiagnosticReportWithDetails", "type": "interface", "file": "types.ts", "definition": "DiagnosticReport & { studentName, generatedByName }", "usedBy": ["data-access-reports.getDiagnosticReports", "actions", "components/report-list.tsx", "components/student-diagnostic-view.tsx"] }, { "name": "ClassMasterySummary", "type": "interface", "file": "types.ts", "definition": "{ classId, className, studentCount, averageMastery, knowledgePointStats[], studentsNeedingAttention[] }", "usedBy": ["data-access.getClassMasterySummary", "data-access-reports.generateClassDiagnosticReport", "components/class-diagnostic-view.tsx"] }, { "name": "KnowledgePointStat", "type": "interface", "file": "types.ts", "definition": "{ knowledgePointId, knowledgePointName, averageMastery, masteredCount(≥80), notMasteredCount(<60), totalStudents }", "usedBy": ["data-access.getKnowledgePointStats", "types.ClassMasterySummary", "components/class-diagnostic-view.tsx"] }, { "name": "DiagnosticReportQueryParams", "type": "interface", "file": "types.ts", "definition": "{ studentId?, reportType?, status?, period? }", "usedBy": ["data-access-reports.getDiagnosticReports", "actions.getDiagnosticReportsAction"] }, { "name": "MasteryRadarPoint", "type": "interface", "file": "types.ts", "definition": "{ knowledgePoint, student(0-100), classAverage?(0-100) }", "usedBy": ["components/mastery-radar-chart.tsx", "components/student-diagnostic-view.tsx", "teacher/diagnostic/student/[studentId]/page.tsx"] } ], "components": [ { "name": "MasteryRadarChart", "file": "components/mastery-radar-chart.tsx", "purpose": "知识点掌握度雷达图(recharts RadarChart,学生 vs 班级平均对比,无数据时显示 EmptyState)", "deps": ["recharts", "shared/components/ui/card", "shared/components/ui/chart", "shared/components/ui/empty-state"] }, { "name": "StudentDiagnosticView", "file": "components/student-diagnostic-view.tsx", "purpose": "学生诊断视图(概览卡片、雷达图、强项/弱项列表、生成报告表单[DIAGNOSTIC_MANAGE]、最新报告与建议展示)", "deps": ["usePermission", "actions.generateStudentReportAction", "components/mastery-radar-chart", "shared/components/ui/*"] }, { "name": "ClassDiagnosticView", "file": "components/class-diagnostic-view.tsx", "purpose": "班级诊断视图(概览卡片、知识点掌握度热力图[绿/黄/橙/红]、知识点排名表、需重点关注学生表[链接到学生视图]、生成班级报告表单[DIAGNOSTIC_MANAGE])", "deps": ["usePermission", "actions.generateClassReportAction", "shared/components/ui/*"] }, { "name": "ReportList", "file": "components/report-list.tsx", "purpose": "诊断报告列表(reportType/status 过滤器[URL searchParams]、报告表格、发布/删除操作[DIAGNOSTIC_MANAGE]、确认对话框)", "deps": ["usePermission", "actions.publishReportAction", "actions.deleteReportAction", "shared/components/ui/*"] } ] } }, "elective": { "path": "src/modules/elective", "description": "选课管理模块:选修课程 CRUD、选课开放/关闭、学生选课/退课、抽签模式批量录取、FCFS 即时录取、DataScope 行级过滤(admin 全部、teacher 所教、grade_head 所管年级、student 可选课程)", "exports": { "actions": [ {"name": "createElectiveCourseAction", "permission": "ELECTIVE_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "创建选修课程(formData: name, subjectId?, teacherId, gradeId?, description?, capacity?, classroom?, schedule?, startDate?, endDate?, selectionStartAt?, selectionEndAt?, selectionMode?, credit?)", "deps": ["requirePermission(ELECTIVE_MANAGE)", "data-access.createElectiveCourse", "revalidatePath"], "usedBy": ["admin/elective/create/page.tsx"]}, {"name": "updateElectiveCourseAction", "permission": "ELECTIVE_MANAGE", "signature": "(id: string, prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "更新选修课程", "deps": ["requirePermission(ELECTIVE_MANAGE)", "data-access.getElectiveCourseById", "data-access.updateElectiveCourse", "revalidatePath"], "usedBy": ["admin/elective/[id]/edit/page.tsx"]}, {"name": "deleteElectiveCourseAction", "permission": "ELECTIVE_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "删除选修课程(formData: courseId)", "deps": ["requirePermission(ELECTIVE_MANAGE)", "data-access.deleteElectiveCourse", "revalidatePath"], "usedBy": ["components/elective-course-list.tsx"]}, {"name": "openSelectionAction", "permission": "ELECTIVE_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "开放选课(formData: courseId)", "deps": ["requirePermission(ELECTIVE_MANAGE)", "data-access.openSelection", "revalidatePath"], "usedBy": ["components/elective-course-list.tsx"]}, {"name": "closeSelectionAction", "permission": "ELECTIVE_MANAGE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "关闭选课(formData: courseId)", "deps": ["requirePermission(ELECTIVE_MANAGE)", "data-access.closeSelection", "revalidatePath"], "usedBy": ["components/elective-course-list.tsx"]}, {"name": "runLotteryAction", "permission": "ELECTIVE_MANAGE", "signature": "(prevState: ActionState<{enrolled:number,waitlist:number}> | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "执行抽签录取(formData: courseId)", "deps": ["requirePermission(ELECTIVE_MANAGE)", "data-access-operations.runLottery", "revalidatePath"], "usedBy": ["components/elective-course-list.tsx"]}, {"name": "selectCourseAction", "permission": "ELECTIVE_SELECT", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "学生选课(formData: courseId, priority?)", "deps": ["requirePermission(ELECTIVE_SELECT)", "data-access-operations.selectCourse", "revalidatePath"], "usedBy": ["components/student-selection-view.tsx"]}, {"name": "dropCourseAction", "permission": "ELECTIVE_SELECT", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "file": "actions.ts", "purpose": "学生退课(formData: courseId)", "deps": ["requirePermission(ELECTIVE_SELECT)", "data-access-operations.dropCourse", "revalidatePath"], "usedBy": ["components/student-selection-view.tsx"]}, {"name": "getElectiveCoursesAction", "permission": "ELECTIVE_READ", "signature": "(params?: GetElectiveCoursesParams) => Promise>", "file": "actions.ts", "purpose": "查询选修课程列表(按 DataScope 过滤)", "deps": ["requirePermission(ELECTIVE_READ)", "data-access.getElectiveCourses (scope, currentUserId)"], "usedBy": ["admin/elective/page.tsx", "teacher/elective/page.tsx"]}, {"name": "getStudentSelectionsAction", "permission": "ELECTIVE_READ", "signature": "(studentId: string) => Promise>", "file": "actions.ts", "purpose": "查询学生选课记录(含 DataScope 二次校验:class_members 仅自己,children 仅子女)", "deps": ["requirePermission(ELECTIVE_READ)", "data-access-selections.getStudentSelections"], "usedBy": ["待扩展"]}, {"name": "getAvailableCoursesAction", "permission": "ELECTIVE_SELECT", "signature": "() => Promise>", "file": "actions.ts", "purpose": "获取学生可选课程(status=open 且匹配年级)", "deps": ["requirePermission(ELECTIVE_SELECT)", "data-access-selections.getAvailableCoursesForStudent"], "usedBy": ["待扩展"]} ], "dataAccess": [ {"name": "getElectiveCourses", "file": "data-access.ts", "signature": "(params?: GetElectiveCoursesParams & { scope?: DataScope; currentUserId?: string }) => Promise", "purpose": "查询选修课程列表(按 scope 行级过滤:owned/class_taught 按 teacherId,grade_managed 按 gradeIds)", "usedBy": ["actions.getElectiveCoursesAction", "admin/elective/page.tsx", "teacher/elective/page.tsx"]}, {"name": "getElectiveCourseById", "file": "data-access.ts", "signature": "(id: string) => Promise", "purpose": "获取课程详情", "usedBy": ["actions.updateElectiveCourseAction", "admin/elective/[id]/edit/page.tsx"]}, {"name": "createElectiveCourse", "file": "data-access.ts", "signature": "(data: CreateElectiveCourseInput, teacherId: string) => Promise", "purpose": "创建选修课程(status=draft, enrolledCount=0)", "usedBy": ["actions.createElectiveCourseAction"]}, {"name": "updateElectiveCourse", "file": "data-access.ts", "signature": "(id: string, data: Partial) => Promise", "purpose": "更新选修课程字段", "usedBy": ["actions.updateElectiveCourseAction"]}, {"name": "deleteElectiveCourse", "file": "data-access.ts", "signature": "(id: string) => Promise", "purpose": "删除选修课程", "usedBy": ["actions.deleteElectiveCourseAction"]}, {"name": "openSelection", "file": "data-access.ts", "signature": "(courseId: string) => Promise", "purpose": "开放选课(status=open)", "usedBy": ["actions.openSelectionAction"]}, {"name": "closeSelection", "file": "data-access.ts", "signature": "(courseId: string) => Promise", "purpose": "关闭选课(status=closed)", "usedBy": ["actions.closeSelectionAction"]}, {"name": "getSubjectOptions", "file": "data-access.ts", "signature": "() => Promise<{id, name}[]>", "purpose": "获取学科选项(按 order, name 排序)", "usedBy": ["admin/elective/create/page.tsx", "admin/elective/[id]/edit/page.tsx"]}, {"name": "getCourseSelections", "file": "data-access-selections.ts", "signature": "(courseId: string) => Promise", "purpose": "查询课程所有选课记录(按 priority, selectedAt 排序)", "usedBy": ["待扩展"]}, {"name": "getStudentSelections", "file": "data-access-selections.ts", "signature": "(studentId: string) => Promise", "purpose": "查询学生选课记录(按 selectedAt 降序)", "usedBy": ["actions.getStudentSelectionsAction", "student/elective/page.tsx"]}, {"name": "getStudentGradeId", "file": "data-access-selections.ts", "signature": "(studentId: string) => Promise", "purpose": "获取学生所在年级 ID(通过 classEnrollments active 记录)", "usedBy": ["data-access-selections.getAvailableCoursesForStudent"]}, {"name": "getAvailableCoursesForStudent", "file": "data-access-selections.ts", "signature": "(studentId: string, gradeId?: string | null) => Promise", "purpose": "获取学生可选课程(status=open 且 gradeId 匹配或为空)", "usedBy": ["actions.getAvailableCoursesAction", "student/elective/page.tsx"]}, {"name": "runLottery", "file": "data-access-operations.ts", "signature": "(courseId: string) => Promise<{enrolled: number, waitlist: number}>", "purpose": "抽签录取(随机打乱 selected 记录,前 capacity 名 enrolled,其余 waitlist,课程 status=closed)", "usedBy": ["actions.runLotteryAction"]}, {"name": "selectCourse", "file": "data-access-operations.ts", "signature": "(courseId: string, studentId: string, priority?: number) => Promise<{status: CourseSelectionStatus, message: string}>", "purpose": "学生选课(校验课程状态/时间窗口/重复选课;FCFS 模式即时 enrolled/waitlist,lottery 模式 selected)", "usedBy": ["actions.selectCourseAction"]}, {"name": "dropCourse", "file": "data-access-operations.ts", "signature": "(courseId: string, studentId: string) => Promise", "purpose": "学生退课(status=dropped;FCFS 模式自动递补 waitlist 首位)", "usedBy": ["actions.dropCourseAction"]} ], "types": [ {"name": "ElectiveCourseStatus", "type": "type", "file": "types.ts", "definition": "\"draft\" | \"open\" | \"closed\" | \"cancelled\""}, {"name": "ElectiveSelectionMode", "type": "type", "file": "types.ts", "definition": "\"fcfs\" | \"lottery\""}, {"name": "CourseSelectionStatus", "type": "type", "file": "types.ts", "definition": "\"selected\" | \"enrolled\" | \"waitlist\" | \"dropped\" | \"rejected\""}, {"name": "ElectiveCourse", "type": "interface", "file": "types.ts", "definition": "{ id, name, subjectId?, teacherId, gradeId?, description?, capacity, enrolledCount, classroom?, schedule?, startDate?, endDate?, selectionStartAt?, selectionEndAt?, status, selectionMode, credit, createdAt, updatedAt }"}, {"name": "ElectiveCourseWithDetails", "type": "interface", "file": "types.ts", "definition": "ElectiveCourse & { teacherName?, subjectName?, gradeName? }"}, {"name": "CourseSelection", "type": "interface", "file": "types.ts", "definition": "{ id, courseId, studentId, status, priority?, selectedAt, enrolledAt?, droppedAt?, lotteryRank?, createdAt, updatedAt }"}, {"name": "CourseSelectionWithDetails", "type": "interface", "file": "types.ts", "definition": "CourseSelection & { courseName?, studentName?, courseCapacity?, courseEnrolledCount?, courseStatus? }"}, {"name": "GetElectiveCoursesParams", "type": "interface", "file": "types.ts", "definition": "{ status?, gradeId?, subjectId?, teacherId? }"}, {"name": "ELECTIVE_STATUS_LABELS", "type": "const", "file": "types.ts", "description": "课程状态标签常量"}, {"name": "ELECTIVE_STATUS_COLORS", "type": "const", "file": "types.ts", "description": "课程状态颜色常量(Badge variant)"}, {"name": "SELECTION_MODE_LABELS", "type": "const", "file": "types.ts", "description": "选课模式标签常量"}, {"name": "COURSE_SELECTION_STATUS_LABELS", "type": "const", "file": "types.ts", "description": "选课状态标签常量"}, {"name": "COURSE_SELECTION_STATUS_COLORS", "type": "const", "file": "types.ts", "description": "选课状态颜色常量(Badge variant)"} ], "schemas": [ {"name": "ElectiveCourseStatusEnum", "file": "schema.ts", "definition": "z.enum([\"draft\",\"open\",\"closed\",\"cancelled\"])"}, {"name": "ElectiveSelectionModeEnum", "file": "schema.ts", "definition": "z.enum([\"fcfs\",\"lottery\"])"}, {"name": "CourseSelectionStatusEnum", "file": "schema.ts", "definition": "z.enum([\"selected\",\"enrolled\",\"waitlist\",\"dropped\",\"rejected\"])"}, {"name": "CreateElectiveCourseSchema", "file": "schema.ts", "purpose": "创建课程校验(name 必填,teacherId 必填,capacity 1-500 默认 30,selectionMode 默认 fcfs,credit 默认 1.0)"}, {"name": "UpdateElectiveCourseSchema", "file": "schema.ts", "purpose": "更新课程校验(所有字段可选,含 status)"}, {"name": "SelectCourseSchema", "file": "schema.ts", "purpose": "选课校验(courseId 必填,priority 1-10 可选)"}, {"name": "DropCourseSchema", "file": "schema.ts", "purpose": "退课校验(courseId 必填)"}, {"name": "RunLotterySchema", "file": "schema.ts", "purpose": "抽签校验(courseId 必填)"} ], "components": [ {"name": "ElectiveCourseList", "file": "components/elective-course-list.tsx", "purpose": "课程卡片列表(管理员/教师视图,含编辑/开放/关闭/抽签/删除操作按钮,usePermission 控制权限)", "deps": ["usePermission", "actions.deleteElectiveCourseAction", "actions.openSelectionAction", "actions.closeSelectionAction", "actions.runLotteryAction", "shared/components/ui/*"]}, {"name": "ElectiveCourseForm", "file": "components/elective-course-form.tsx", "purpose": "课程创建/编辑表单(name, subjectId, teacherId, gradeId, description, capacity, classroom, schedule, dates, selectionMode, credit)", "deps": ["react-hook-form", "actions.createElectiveCourseAction", "actions.updateElectiveCourseAction", "shared/components/ui/*"]}, {"name": "StudentSelectionView", "file": "components/student-selection-view.tsx", "purpose": "学生选课视图(可选课程列表 + 我的选课记录,含选课/退课按钮)", "deps": ["usePermission", "actions.selectCourseAction", "actions.dropCourseAction", "shared/components/ui/*"]} ] } } }, "dependencyMatrix": { "shared": {"dependsOn": []}, "auth": {"dependsOn": ["shared"], "uses": {"shared": ["db", "schema", "permissions"]}}, "exams": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard", "types", "ai"], "auth": ["auth"]}}, "homework": {"dependsOn": ["shared", "auth", "exams"], "uses": {"shared": ["db", "auth-guard", "types"], "auth": ["auth"], "exams": ["data-access.getExams"]}}, "questions": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard", "types"], "auth": ["auth"]}}, "textbooks": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard", "types"], "auth": ["auth"]}}, "classes": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard", "types"], "auth": ["auth"]}}, "school": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard", "types"], "auth": ["auth"]}}, "dashboard": {"dependsOn": ["shared", "auth", "homework", "classes"], "uses": {"shared": ["db", "types"], "auth": ["auth"], "homework": ["data-access.getTeacherGradeTrends", "data-access.getStudentDashboardGrades"], "classes": ["data-access.getTeacherClasses", "data-access.getStudentClasses", "data-access.getStudentSchedule"]}}, "layout": {"dependsOn": ["shared", "auth", "messaging"], "uses": {"shared": ["hooks.usePermission", "components.global-search.GlobalSearch"], "auth": ["useSession"], "messaging": ["components.notification-dropdown"]}}, "settings": {"dependsOn": ["shared", "auth", "messaging"], "uses": {"shared": ["db", "auth-guard", "ai", "types", "components.ui.switch"], "auth": ["auth"], "messaging": ["notification-preferences.getNotificationPreferences", "actions.getNotificationPreferencesAction", "actions.updateNotificationPreferencesAction"]}}, "users": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard.requireAuth", "auth-guard.requirePermission", "db.schema.users", "db.schema.roles", "db.schema.usersToRoles", "db.schema.classes", "db.schema.classEnrollments", "types.permissions", "types.action-state", "lib.excel"], "auth": ["auth"]}}, "audit": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard.requirePermission", "db.schema.auditLogs", "db.schema.loginLogs", "db.schema.dataChangeLogs", "types.permissions", "lib.excel"], "auth": ["auth"]}}, "announcements": {"dependsOn": ["shared", "auth", "school"], "uses": {"shared": ["db", "auth-guard.requirePermission", "auth-guard.requireAuth", "db.schema.announcements", "types.permissions"], "auth": ["auth"], "school": ["data-access.getGrades"]}}, "files": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard.requireAuth", "auth-guard.requirePermission", "types.permissions", "lib.file-storage", "lib.storage-provider"], "auth": ["auth"]}}, "course-plans": {"dependsOn": ["shared", "auth", "school", "classes"], "uses": {"shared": ["db", "auth-guard.requirePermission", "db.schema.coursePlans", "db.schema.coursePlanItems", "db.schema.classes", "db.schema.subjects", "db.schema.users", "types.permissions", "types.action-state"], "auth": ["auth"], "school": ["data-access.getAcademicYears"], "classes": ["data-access.getAdminClasses", "data-access.getStaffOptions"]}}, "grades": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard.requirePermission", "types.permissions", "types.action-state", "db.schema.gradeRecords", "db.schema.classes", "db.schema.classEnrollments", "db.schema.subjects", "db.schema.users", "lib.excel"], "auth": ["auth"]}}, "parent": {"dependsOn": ["shared", "auth", "homework", "classes", "grades"], "uses": {"shared": ["db", "auth-guard.requireAuth", "db.schema.parentStudentRelations", "db.schema.users", "db.schema.grades", "db.schema.classEnrollments", "db.schema.classes", "types"], "auth": ["auth"], "homework": ["data-access.getStudentHomeworkAssignments", "data-access.getStudentDashboardGrades"], "classes": ["data-access.getStudentClasses", "data-access.getStudentSchedule"], "grades": ["data-access.getStudentGradeSummary"]}}, "messaging": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard.requirePermission", "auth-guard.requireAuth", "db.schema.messages", "db.schema.messageNotifications", "db.schema.notificationPreferences", "db.schema.users", "db.schema.classEnrollments", "db.schema.classes", "db.schema.grades", "types.permissions", "types.action-state"], "auth": ["auth"]}}, "attendance": {"dependsOn": ["shared", "auth", "classes"], "uses": {"shared": ["db", "auth-guard.requirePermission", "db.schema.attendanceRecords", "db.schema.attendanceRules", "db.schema.classEnrollments", "db.schema.users", "db.schema.classes", "types.permissions", "types.action-state", "types.DataScope"], "auth": ["auth"], "classes": ["data-access.getTeacherClasses", "data-access.getAdminClasses"]}}, "scheduling": {"dependsOn": ["shared", "auth", "classes"], "uses": {"shared": ["db", "auth-guard.requirePermission", "auth-guard.getAuthContext", "db.schema.schedulingRules", "db.schema.scheduleChanges", "db.schema.classSchedule", "db.schema.classes", "db.schema.users", "db.schema.classSubjectTeachers", "db.schema.subjects", "db.schema.classrooms", "types.permissions", "types.action-state"], "auth": ["auth"], "classes": []}}, "diagnostic": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard.requirePermission", "auth-guard.getAuthContext", "db.schema.knowledgePointMastery", "db.schema.learningDiagnosticReports", "db.schema.knowledgePoints", "db.schema.questionsToKnowledgePoints", "db.schema.examSubmissions", "db.schema.submissionAnswers", "db.schema.classEnrollments", "db.schema.classes", "db.schema.users", "types.permissions", "types.action-state", "hooks.usePermission", "components.ui.*"], "auth": ["auth"]}}, "elective": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard.requirePermission", "db.schema.electiveCourses", "db.schema.courseSelections", "db.schema.users", "db.schema.subjects", "db.schema.grades", "db.schema.classes", "db.schema.classEnrollments", "types.permissions", "types.action-state", "types.DataScope", "hooks.usePermission", "components.ui.*"], "auth": ["auth"]}} }, "parameterFlowChains": { "userId": { "origin": "auth.ts JWT callback 从 users 表查询", "flow": [ "auth.ts → session.user.id (JWT存储)", "session.user.id → Server Components (通过auth())", "session.user.id → Client Components (通过useSession())", "getAuthContext().userId → 所有Server Actions", "auth-guard.ts → 查询 usersToRoles (获取角色)", "auth-guard.ts → 查询 classSubjectTeachers/grades (获取DataScope)", "exams/actions.ts → 作为 creatorId 写入 exams 表", "homework/actions.ts → 作为 creatorId 写入 homeworkAssignments 表", "classes/data-access.ts → getTeacherClasses(teacherId), getGradeManagedClasses(userId)", "grades/actions.ts → 作为 recordedBy 写入 gradeRecords 表", "attendance/actions.ts → 作为 recordedBy 写入 attendanceRecords 表", "elective/actions.ts → 作为 teacherId 默认值写入 electiveCourses 表(createElectiveCourseAction)", "elective/actions.ts → 作为 studentId 查询学生选课(selectCourseAction/dropCourseAction/getStudentSelectionsAction)", "elective/data-access.ts → getElectiveCourses({ scope, currentUserId }) 按 teacherId 过滤(class_taught/owned)" ] }, "examId": { "origin": "exams/actions.ts createExamAction 产生 (CUID2)", "flow": [ "createExamAction → 写入 exams.id", "exams/data-access.getExamById(id) → 读取考试详情", "updateExamAction/deleteExamAction/duplicateExamAction → 定位考试", "homework/actions.ts createHomeworkAssignmentAction → sourceExamId 参数", "homeworkAssignments.sourceExamId → 外键关联源考试", "homework/data-access.getHomeworkAssignmentAnalytics → 追溯作业来源" ] }, "classId": { "origin": "classes/actions.ts createTeacherClassAction/createAdminClassAction 产生", "flow": [ "createTeacherClassAction → 写入 classes.id", "classes/data-access.getClassStudents(classId) → 学生列表", "classes/data-access.getClassSchedule(classId) → 课表", "classes/data-access.getClassHomeworkInsights(classId) → 作业洞察", "homework/data-access.getHomeworkAssignments({ classId }) → 过滤作业", "auth-guard.ts → classSubjectTeachers 查询 → DataScope.class_taught.classIds", "grades/data-access.getGradeRecords({ classId }) → 过滤成绩列表", "grades/data-access.getClassGradeStats(classId) → 班级成绩统计", "grades/data-access.getClassRanking(classId) → 班级排名", "attendance/data-access.getAttendanceRecords({ classId }) → 过滤考勤记录", "attendance/data-access.getClassAttendanceForDate(classId, date) → 班级指定日期考勤", "attendance/data-access-stats.getClassAttendanceStats(classId) → 班级考勤统计" ] }, "permission": { "origin": "shared/types/permissions.ts Permissions 常量定义(50 个权限点,含 FILE_UPLOAD/FILE_READ/FILE_DELETE、GRADE_RECORD_MANAGE/GRADE_RECORD_READ、ATTENDANCE_MANAGE/ATTENDANCE_READ、MESSAGE_SEND/MESSAGE_READ/MESSAGE_DELETE、SCHEDULE_AUTO/SCHEDULE_ADJUST、ELECTIVE_MANAGE/ELECTIVE_READ/ELECTIVE_SELECT)", "flow": [ "shared/lib/permissions.ts ROLE_PERMISSIONS → 角色到权限映射(admin/teacher 拥有全部 FILE_* 及 GRADE_RECORD_MANAGE/READ,student/parent/grade_head/teaching_head 拥有 GRADE_RECORD_READ;admin/teacher 拥有 ATTENDANCE_MANAGE+ATTENDANCE_READ,student/parent/grade_head/teaching_head 拥有 ATTENDANCE_READ;admin/teacher/parent/grade_head/teaching_head 拥有 MESSAGE_SEND/READ/DELETE,student 拥有 MESSAGE_READ/DELETE 但无 MESSAGE_SEND;admin 拥有 SCHEDULE_AUTO+SCHEDULE_ADJUST,teacher 无排课权限;admin/teacher 拥有 ELECTIVE_MANAGE+ELECTIVE_READ,student 拥有 ELECTIVE_SELECT+ELECTIVE_READ,grade_head/teaching_head 拥有 ELECTIVE_READ)", "auth.ts JWT callback → resolvePermissions(roleNames) → token.permissions", "proxy.ts middleware → token.permissions → 路由权限检查", "auth-guard.ts requirePermission(permission) → Server Action权限断言(如 /api/files/[id] DELETE 使用 FILE_DELETE;grades/actions.ts 使用 GRADE_RECORD_MANAGE/READ;messaging/actions.ts 使用 MESSAGE_SEND/READ/DELETE;attendance/actions.ts 使用 ATTENDANCE_MANAGE/READ;scheduling/actions.ts 使用 SCHEDULE_AUTO/SCHEDULE_ADJUST;elective/actions.ts 使用 ELECTIVE_MANAGE/READ/SELECT)", "auth-guard.ts requireAuth() → 仅校验登录(如 /api/upload POST、/api/files/[id] GET、messaging 通知读取 actions)", "use-permission.ts hasPermission(permission) → 客户端条件渲染(如 file-list.tsx 删除按钮可见性;message-list/detail.tsx 写消息/删除按钮可见性;elective-course-list.tsx 操作按钮可见性)", "layout/config/navigation.ts NavItem.permission → 侧边栏菜单过滤(Grades 菜单项使用 GRADE_RECORD_READ;Messages 菜单项使用 MESSAGE_READ;Attendance 菜单项 teacher 使用 ATTENDANCE_MANAGE,student/parent 使用 ATTENDANCE_READ;Scheduling 菜单项 admin 使用 SCHEDULE_ADJUST/SCHEDULE_AUTO,teacher Schedule Changes 使用 SCHEDULE_ADJUST;Electives 菜单项 admin/teacher 使用 ELECTIVE_MANAGE,student 使用 ELECTIVE_SELECT)" ] }, "dataScope": { "origin": "auth-guard.ts resolveDataScope(userId, roles) 动态计算", "flow": [ "resolveDataScope → AuthContext.dataScope", "exams/data-access.getExams({ scope }) → 行级过滤", "homework/data-access.getHomeworkAssignments({ scope }) → 行级过滤", "dashboard/data-access.getAdminDashboardData(scope) → 统计过滤", "exams/actions.ts update/delete → scope.type !== 'all' 时校验资源归属", "grades/data-access.getGradeRecords({ scope }) → 行级过滤(class_taught 限制所教班级,class_members 限制学生本人,children 限制子女)", "attendance/data-access.getAttendanceRecords({ scope }) → 行级过滤(class_taught 按教师班级过滤,children 按子女过滤,class_members 仅查自己,all 查全部)", "attendance/actions.ts getStudentAttendanceAction → 对 class_members/children 进行 DataScope 二次校验", "elective/data-access.getElectiveCourses({ scope, currentUserId }) → 行级过滤(owned/class_taught 按 teacherId 过滤,grade_managed 按 gradeIds 过滤,class_members/children 返回 null 由 getAvailableCoursesForStudent 处理)", "elective/actions.ts getStudentSelectionsAction → 对 class_members/children 进行 DataScope 二次校验" ] } }, "routes": { "auth": { "/login": {"component": "LoginForm", "type": "client", "module": "auth"}, "/register": {"component": "RegisterForm + registerAction", "type": "server", "module": "auth", "description": "注册页面(含未成年人信息保护、隐私政策/用户协议同意勾选)"}, "/privacy": {"component": "PrivacyPage", "type": "server", "module": "auth", "description": "隐私政策页面(信息收集/使用/保护、用户权利、Cookie、未成年人保护条款、联系方式)"}, "/terms": {"component": "TermsPage", "type": "server", "module": "auth", "description": "用户协议页面(服务说明、注册、行为规范、知识产权、免责、变更终止、法律适用)"} }, "admin": { "/admin/dashboard": {"component": "AdminDashboardView", "type": "server", "dataAccess": ["dashboard/data-access.getAdminDashboardData"], "permission": "school:manage"}, "/admin/school": {"component": "重定向", "type": "server", "redirect": "/admin/school/classes", "permission": "school:manage"}, "/admin/school/schools": {"component": "SchoolsClient", "type": "client", "module": "school", "permission": "school:manage"}, "/admin/school/grades": {"component": "GradesClient", "type": "client", "module": "school", "permission": "grade:manage"}, "/admin/school/grades/insights": {"component": "年级作业洞察", "type": "server", "dataAccess": ["classes/data-access.getGradeHomeworkInsights"], "permission": "grade:manage"}, "/admin/school/departments": {"component": "DepartmentsClient", "type": "client", "module": "school", "permission": "school:manage"}, "/admin/school/classes": {"component": "AdminClassesClient", "type": "client", "module": "classes", "permission": "school:manage"}, "/admin/school/academic-year": {"component": "AcademicYearClient", "type": "client", "module": "school", "permission": "school:manage"}, "/admin/audit-logs": {"component": "AuditLogView", "type": "server", "module": "audit", "dataAccess": ["audit/data-access.getAuditLogs", "audit/data-access.getAuditModuleOptions"], "permission": "audit_log:read"}, "/admin/audit-logs/login-logs": {"component": "LoginLogView", "type": "server", "module": "audit", "dataAccess": ["audit/data-access.getLoginLogs"], "permission": "audit_log:read"}, "/admin/announcements": {"component": "AdminAnnouncementsView", "type": "server", "module": "announcements", "dataAccess": ["announcements/data-access.getAnnouncements", "school/data-access.getGrades"], "actions": ["createAnnouncementAction"], "permission": "announcement:manage"}, "/admin/announcements/[id]": {"component": "AnnouncementForm (edit)", "type": "server", "module": "announcements", "dataAccess": ["announcements/data-access.getAnnouncementById", "school/data-access.getGrades"], "actions": ["updateAnnouncementAction"], "permission": "announcement:manage"}, "/admin/files": {"component": "AdminFilesView", "type": "server", "module": "files", "dataAccess": ["files/data-access.getAllFileAttachments"], "permission": "file:read"}, "/admin/course-plans": {"component": "CoursePlanList", "type": "client", "module": "course-plans", "dataAccess": ["course-plans/data-access.getCoursePlans"], "permission": "course_plan:manage"}, "/admin/course-plans/create": {"component": "CoursePlanForm (create)", "type": "client", "module": "course-plans", "actions": ["createCoursePlanAction"], "dataAccess": ["classes/data-access.getAdminClasses", "course-plans/data-access.getSubjectOptions", "classes/data-access.getStaffOptions", "school/data-access.getAcademicYears"], "permission": "course_plan:manage"}, "/admin/course-plans/[id]": {"component": "CoursePlanDetail", "type": "client", "module": "course-plans", "dataAccess": ["course-plans/data-access.getCoursePlanById"], "actions": ["deleteCoursePlanAction", "createCoursePlanItemAction", "updateCoursePlanItemAction", "deleteCoursePlanItemAction", "toggleCoursePlanItemCompletedAction"], "permission": "course_plan:manage"}, "/admin/course-plans/[id]/edit": {"component": "CoursePlanForm (edit)", "type": "client", "module": "course-plans", "actions": ["updateCoursePlanAction"], "dataAccess": ["course-plans/data-access.getCoursePlanById", "classes/data-access.getAdminClasses", "course-plans/data-access.getSubjectOptions", "classes/data-access.getStaffOptions", "school/data-access.getAcademicYears"], "permission": "course_plan:manage"}, "/admin/attendance": {"component": "AttendanceRecordList", "type": "server", "module": "attendance", "dataAccess": ["attendance/data-access.getAttendanceRecords (scope=all)", "classes/data-access.getAdminClasses"], "permission": "attendance:manage", "description": "管理员考勤总览(权限:requirePermission(ATTENDANCE_MANAGE))"}, "/admin/users/import": {"component": "UserImportPage (含 UserImportDialog)", "type": "server", "module": "users", "actions": ["users/actions.downloadUserTemplateAction", "users/actions.importUsersAction"], "permission": "user:manage", "description": "用户批量导入页面(说明卡片+字段文档表+导入对话框;权限:requirePermission(USER_MANAGE))"}, "/admin/scheduling/rules": {"component": "SchedulingRulesForm", "type": "server", "module": "scheduling", "dataAccess": ["scheduling/actions.getAdminClassesForScheduling", "scheduling/actions.getSchedulingRules"], "actions": ["saveSchedulingRulesAction"], "permission": "schedule:adjust", "description": "排课规则配置页面(权限:requirePermission(SCHEDULE_ADJUST))"}, "/admin/scheduling/auto": {"component": "AutoSchedulePanel + AutoScheduleResultView", "type": "server", "module": "scheduling", "dataAccess": ["scheduling/actions.getAdminClassesForScheduling"], "actions": ["autoScheduleAction", "applyAutoScheduleAction"], "permission": "schedule:auto", "description": "自动排课页面(预览+应用;权限:requirePermission(SCHEDULE_AUTO))"}, "/admin/scheduling/changes": {"component": "ScheduleChangeList + ScheduleConflictsView", "type": "server", "module": "scheduling", "dataAccess": ["scheduling/actions.getAdminClassesForScheduling", "scheduling/actions.getScheduleChanges"], "actions": ["approveScheduleChangeAction", "rejectScheduleChangeAction", "getClassConflictsAction"], "permission": "schedule:adjust", "description": "调课申请审批+冲突检测页面(权限:requirePermission(SCHEDULE_ADJUST);审批操作需 SCHEDULE_AUTO)"}, "/admin/elective": {"component": "ElectiveCourseList", "type": "server", "module": "elective", "dataAccess": ["elective/data-access.getElectiveCourses (scope=all)"], "actions": ["deleteElectiveCourseAction", "openSelectionAction", "closeSelectionAction", "runLotteryAction"], "permission": "elective:manage", "description": "管理员选修课程列表(权限:requirePermission(ELECTIVE_MANAGE))"}, "/admin/elective/create": {"component": "ElectiveCourseForm", "type": "client", "module": "elective", "actions": ["createElectiveCourseAction"], "dataAccess": ["elective/data-access.getSubjectOptions"], "permission": "elective:manage", "description": "创建选修课程(权限:requirePermission(ELECTIVE_MANAGE))"}, "/admin/elective/[id]/edit": {"component": "ElectiveCourseForm (edit)", "type": "client", "module": "elective", "actions": ["updateElectiveCourseAction"], "dataAccess": ["elective/data-access.getElectiveCourseById", "elective/data-access.getSubjectOptions"], "permission": "elective:manage", "description": "编辑选修课程(权限:requirePermission(ELECTIVE_MANAGE))"} }, "teacher": { "/teacher/dashboard": {"component": "TeacherDashboardView", "type": "server", "dataAccess": ["dashboard/data-access (teacher)", "homework/data-access.getTeacherGradeTrends", "classes/data-access.getTeacherClasses"], "permission": "exam:read"}, "/teacher/exams/all": {"component": "ExamDataTable", "type": "server", "dataAccess": ["exams/data-access.getExams"], "permission": "exam:read"}, "/teacher/exams/create": {"component": "ExamForm", "type": "client", "actions": ["createExamAction", "createAiExamAction", "previewAiExamAction"], "permission": "exam:create"}, "/teacher/questions": {"component": "QuestionDataTable", "type": "server", "dataAccess": ["questions/data-access.getQuestions"], "permission": "question:read"}, "/teacher/textbooks": {"component": "TextbookList", "type": "server", "dataAccess": ["textbooks/data-access.getTextbooks"], "permission": "textbook:read"}, "/teacher/textbooks/[id]": {"component": "TextbookReader", "type": "client", "dataAccess": ["textbooks/data-access.getTextbookById", "getChaptersByTextbookId", "getKnowledgePointsByTextbookId"], "permission": "textbook:read"}, "/teacher/classes/my": {"component": "ClassList", "type": "server", "dataAccess": ["classes/data-access.getTeacherClasses"], "permission": "class:read"}, "/teacher/classes/schedule": {"component": "ClassSchedule", "type": "server", "dataAccess": ["classes/data-access.getClassSchedule"], "permission": "class:read"}, "/teacher/classes/students": {"component": "ClassStudents", "type": "server", "dataAccess": ["classes/data-access.getClassStudents"], "permission": "class:read"}, "/teacher/classes": {"component": "重定向", "type": "server", "redirect": "/teacher/classes/my", "permission": "class:read"}, "/teacher/classes/my/[id]": {"component": "班级详情", "type": "client", "module": "classes", "dataAccess": ["classes/data-access.getClassStudents", "classes/data-access.getClassSchedule", "classes/data-access.getClassHomeworkInsights"], "permission": "class:read"}, "/teacher/homework": {"component": "重定向", "type": "server", "redirect": "/teacher/homework/assignments", "permission": "homework:create"}, "/teacher/homework/assignments": {"component": "作业列表", "type": "server", "module": "homework", "dataAccess": ["homework/data-access.getHomeworkAssignments"], "permission": "homework:create"}, "/teacher/homework/assignments/create": {"component": "HomeworkAssignmentForm", "type": "client", "module": "homework", "actions": ["createHomeworkAssignmentAction"], "permission": "homework:create"}, "/teacher/homework/assignments/[id]": {"component": "作业详情+错误分析", "type": "client", "module": "homework", "dataAccess": ["homework/data-access.getHomeworkAssignmentById", "homework/data-access.getHomeworkAssignmentAnalytics"], "permission": "homework:create"}, "/teacher/homework/assignments/[id]/submissions": {"component": "作业提交列表", "type": "server", "module": "homework", "dataAccess": ["homework/data-access.getHomeworkSubmissions"], "permission": "homework:create"}, "/teacher/homework/submissions": {"component": "批改列表", "type": "server", "module": "homework", "dataAccess": ["homework/data-access.getHomeworkAssignmentReviewList"], "permission": "homework:grade"}, "/teacher/homework/submissions/[submissionId]": {"component": "HomeworkGradingView", "type": "client", "module": "homework", "actions": ["gradeHomeworkSubmissionAction"], "dataAccess": ["homework/data-access.getHomeworkSubmissionDetails"], "permission": "homework:grade"}, "/teacher/exams": {"component": "重定向", "type": "server", "redirect": "/teacher/exams/all", "permission": "exam:read"}, "/teacher/exams/[id]/build": {"component": "ExamAssembly", "type": "client", "module": "exams", "permission": "exam:update"}, "/teacher/exams/grading": {"component": "重定向", "type": "server", "redirect": "/teacher/homework/submissions", "permission": "homework:grade"}, "/teacher/exams/grading/[submissionId]": {"component": "重定向", "type": "server", "redirect": "/teacher/homework/submissions", "permission": "homework:grade"}, "/teacher/grades": {"component": "成绩管理首页", "type": "server", "module": "grades", "dataAccess": ["grades/actions.getGradeRecordsAction"], "permission": "grade_record:read"}, "/teacher/grades/entry": {"component": "批量成绩录入", "type": "server", "module": "grades", "actions": ["grades/actions.batchCreateGradeRecordsAction", "grades/actions.createGradeRecordAction"], "permission": "grade_record:manage"}, "/teacher/grades/stats": {"component": "成绩统计报表", "type": "server", "module": "grades", "dataAccess": ["grades/actions.getClassGradeStatsAction", "grades/actions.getClassRankingAction"], "permission": "grade_record:read"}, "/teacher/course-plans": {"component": "CoursePlanList (teacher)", "type": "client", "module": "course-plans", "dataAccess": ["course-plans/data-access.getCoursePlans (filtered by teacherId)"], "permission": "course_plan:read"}, "/teacher/course-plans/[id]": {"component": "CoursePlanDetail (teacher, read-only)", "type": "client", "module": "course-plans", "dataAccess": ["course-plans/data-access.getCoursePlanById"], "permission": "course_plan:read"}, "/teacher/attendance": {"component": "AttendanceRecordList + AttendanceFilters", "type": "server", "module": "attendance", "dataAccess": ["attendance/data-access.getAttendanceRecords", "classes/data-access.getTeacherClasses"], "permission": "attendance:manage", "description": "教师考勤记录列表(权限:requirePermission(ATTENDANCE_MANAGE))"}, "/teacher/attendance/sheet": {"component": "AttendanceSheet", "type": "client", "module": "attendance", "actions": ["batchRecordAttendanceAction", "getClassAttendanceForDateAction"], "dataAccess": ["attendance/data-access.getClassStudentsForAttendance"], "permission": "attendance:manage", "description": "批量点名页面(权限:requirePermission(ATTENDANCE_MANAGE))"}, "/teacher/attendance/stats": {"component": "AttendanceStatsCard", "type": "server", "module": "attendance", "dataAccess": ["attendance/data-access-stats.getClassAttendanceStats", "classes/data-access.getTeacherClasses"], "permission": "attendance:read", "description": "班级考勤统计(权限:requirePermission(ATTENDANCE_READ))"}, "/teacher/schedule-changes": {"component": "ScheduleChangeForm + ScheduleChangeList", "type": "server", "module": "scheduling", "dataAccess": ["scheduling/actions.getAdminClassesForScheduling", "scheduling/actions.getTeachersForScheduling", "scheduling/actions.getScheduleChanges (requesterId=ctx.userId)"], "actions": ["requestScheduleChangeAction"], "permission": "schedule:adjust", "description": "教师调课/代课申请页面(提交申请+查看本人申请列表;权限:requirePermission(SCHEDULE_ADJUST);admin 角色查看全部申请)"}, "/teacher/diagnostic": {"component": "ReportList", "type": "client", "module": "diagnostic", "dataAccess": ["diagnostic/data-access-reports.getDiagnosticReports"], "actions": ["publishReportAction", "deleteReportAction"], "permission": "diagnostic:read", "description": "学情诊断报告列表(reportType/status 过滤器;权限:requirePermission(DIAGNOSTIC_READ);DataScope.class_members 仅查看自己报告;发布/删除操作需 DIAGNOSTIC_MANAGE)"}, "/teacher/diagnostic/student/[studentId]": {"component": "StudentDiagnosticView", "type": "client", "module": "diagnostic", "dataAccess": ["diagnostic/data-access.getStudentMasterySummary", "diagnostic/data-access.getKnowledgePointStats (班级平均对比)", "diagnostic/data-access-reports.getDiagnosticReports"], "actions": ["generateStudentReportAction"], "permission": "diagnostic:read", "description": "学生学情诊断视图(概览卡片+雷达图+强项/弱项+生成报告[DIAGNOSTIC_MANAGE]+最新报告;权限:getAuthContext + DataScope 二次校验,class_members 仅自己,children 仅子女)"}, "/teacher/diagnostic/class/[classId]": {"component": "ClassDiagnosticView", "type": "client", "module": "diagnostic", "dataAccess": ["diagnostic/data-access.getClassMasterySummary"], "actions": ["generateClassReportAction"], "permission": "diagnostic:read", "description": "班级学情诊断视图(概览+知识点热力图+排名表+需重点关注学生+生成班级报告[DIAGNOSTIC_MANAGE];权限:getAuthContext + DataScope 校验,class_taught 必须包含 classId,class_members/children notFound)"}, "/teacher/elective": {"component": "ElectiveCourseList (teacher)", "type": "server", "module": "elective", "dataAccess": ["elective/data-access.getElectiveCourses (scope=class_taught/owned, currentUserId)"], "actions": ["deleteElectiveCourseAction", "openSelectionAction", "closeSelectionAction", "runLotteryAction"], "permission": "elective:manage", "description": "教师选修课程列表(权限:requirePermission(ELECTIVE_MANAGE);DataScope.class_taught/owned 按 teacherId 过滤)"} }, "student": { "/student/dashboard": {"component": "StudentDashboardView", "type": "server", "dataAccess": ["dashboard/data-access (student)", "homework/data-access.getStudentDashboardGrades", "classes/data-access.getStudentClasses"], "permission": "homework:submit"}, "/student/learning/assignments": {"component": "学生作业列表", "type": "server", "module": "homework", "dataAccess": ["homework/data-access.getStudentHomeworkAssignments"], "permission": "homework:submit"}, "/student/learning/assignments/[assignmentId]": {"component": "学生作答/复习", "type": "client", "module": "homework", "actions": ["startHomeworkSubmissionAction", "saveHomeworkAnswerAction", "submitHomeworkAction"], "dataAccess": ["homework/data-access.getStudentHomeworkTakeData"], "permission": "homework:submit"}, "/student/learning/courses": {"component": "StudentCoursesView", "type": "server", "permission": "homework:submit"}, "/student/learning/textbooks": {"component": "学生教材列表(只读)", "type": "server", "module": "textbooks", "dataAccess": ["textbooks/data-access.getTextbooks"], "permission": "textbook:read"}, "/student/learning/textbooks/[id]": {"component": "学生教材阅读(只读)", "type": "client", "module": "textbooks", "dataAccess": ["textbooks/data-access.getTextbookById", "getChaptersByTextbookId", "getKnowledgePointsByTextbookId"], "permission": "textbook:read"}, "/student/schedule": {"component": "学生课表", "type": "server", "module": "classes", "dataAccess": ["classes/data-access.getStudentSchedule"], "permission": "homework:submit"}, "/student/grades": {"component": "我的成绩", "type": "server", "module": "grades", "dataAccess": ["grades/actions.getStudentGradeSummaryAction"], "permission": "grade_record:read"}, "/student/attendance": {"component": "StudentAttendanceView", "type": "server", "module": "attendance", "dataAccess": ["attendance/data-access-stats.getStudentAttendanceSummary"], "permission": "attendance:read", "description": "学生考勤视图(统计卡片 + 最近记录;权限:requirePermission(ATTENDANCE_READ),DataScope.class_members 仅查自己)"}, "/student/diagnostic": {"component": "StudentDiagnosticView", "type": "client", "module": "diagnostic", "dataAccess": ["diagnostic/data-access.getStudentMasterySummary (ctx.userId)", "diagnostic/data-access-reports.getDiagnosticReports (studentId=ctx.userId)"], "permission": "diagnostic:read", "description": "学生本人学情诊断视图(概览+雷达图+强项/弱项+最新报告;权限:requirePermission(DIAGNOSTIC_READ),DataScope.class_members 仅查自己)"}, "/student/elective": {"component": "StudentSelectionView", "type": "server", "module": "elective", "dataAccess": ["elective/data-access-selections.getAvailableCoursesForStudent", "elective/data-access-selections.getStudentSelections"], "actions": ["selectCourseAction", "dropCourseAction"], "permission": "elective:select", "description": "学生选课页面(可选课程列表 + 我的选课记录;权限:requirePermission(ELECTIVE_SELECT))"} }, "management": { "/management/grade/classes": {"component": "GradeClassesClient", "type": "client", "module": "classes", "permission": "grade:manage"}, "/management/grade/insights": {"component": "年级作业洞察", "type": "server", "dataAccess": ["classes/data-access.getGradeHomeworkInsights"], "permission": "grade:manage"} }, "parent": { "/parent/dashboard": {"component": "ParentDashboard", "type": "server", "module": "parent", "dataAccess": ["parent/data-access.getParentDashboardData"], "permission": "auth_required", "description": "家长仪表盘首页(问候语 + 子女卡片网格;权限:requireAuth())"}, "/parent/children/[studentId]": {"component": "ChildDetailHeader + ChildDetailPanel", "type": "server", "module": "parent", "dataAccess": ["parent/data-access.getChildDashboardData"], "permission": "auth_required", "description": "子女详情页(头部 + 作业/成绩/课表面板;权限:requireAuth() + 二次校验 ctx.dataScope.childrenIds 包含 studentId)"}, "/parent/grades": {"component": "子女成绩", "type": "server", "module": "grades", "dataAccess": ["grades/data-access.getStudentGradeSummary"], "permission": "grade_record:read", "description": "家长成绩视图(按 DataScope.children 过滤)"}, "/parent/attendance": {"component": "StudentAttendanceView (per child)", "type": "server", "module": "attendance", "dataAccess": ["parent/data-access.getChildren", "attendance/data-access-stats.getStudentAttendanceSummary"], "permission": "attendance:read", "description": "家长考勤视图(遍历子女,每个子女展示 StudentAttendanceView;权限:requirePermission(ATTENDANCE_READ),DataScope.children 仅查子女)"} }, "root": { "/": {"component": "重定向", "type": "server", "redirect": "/dashboard"} }, "shared": { "/dashboard": {"component": "角色路由分发", "type": "server", "redirect": "按permissions判断→/admin|/teacher|/student|/parent"}, "/profile": {"component": "ProfilePage", "type": "server", "permission": "auth_required"}, "/settings": {"component": "SettingsPage", "type": "server", "permission": "auth_required", "dataAccess": ["messaging/notification-preferences.getNotificationPreferences"], "description": "设置页面(按角色分发 AdminSettingsView/TeacherSettingsView/StudentSettingsView;含 General/Appearance/Security/Notifications tab,Notifications 渲染 NotificationPreferencesForm)"}, "/announcements": {"component": "AnnouncementList (published only)", "type": "server", "module": "announcements", "dataAccess": ["announcements/data-access.getAnnouncements (status=published)"], "permission": "announcement:read"} }, "messages": { "/messages": {"component": "MessageList + NotificationList", "type": "server", "module": "messaging", "dataAccess": ["messaging/data-access.getMessages", "messaging/data-access.getNotifications"], "permission": "message:read", "description": "消息首页(收件箱/已发送列表 + 通知列表;权限:requirePermission(MESSAGE_READ))"}, "/messages/[id]": {"component": "MessageDetail", "type": "server", "module": "messaging", "dataAccess": ["messaging/data-access.getMessageById", "messaging/data-access.getMessageThread"], "actions": ["markMessageAsReadAction (自动已读)"], "permission": "message:read", "description": "消息详情(含回复线程;权限:requirePermission(MESSAGE_READ))"}, "/messages/compose": {"component": "MessageCompose", "type": "server", "module": "messaging", "dataAccess": ["messaging/data-access.getRecipients"], "permission": "message:send", "description": "写消息页面(支持 reply 模式 via searchParams: receiverId, subject, parentMessageId;权限:requirePermission(MESSAGE_SEND))"} } }, "apiRoutes": { "/api/auth/[...nextauth]": {"methods": ["GET", "POST"], "handler": "auth.handlers", "auth": "public"}, "/api/ai/chat": {"methods": ["POST"], "handler": "createAiChatCompletion", "auth": "AI_CHAT", "validation": "parseAiChatPayload (Zod)"}, "/api/onboarding/complete": {"methods": ["POST"], "handler": "onboarding complete", "auth": "required", "validation": "Zod schema"}, "/api/onboarding/status": {"methods": ["GET"], "handler": "onboarding status", "auth": "required"}, "/api/upload": {"methods": ["POST"], "handler": "文件上传 (multipart/form-data)", "auth": "requireAuth", "module": "files", "validation": "isAllowedMimeType + MAX_FILE_SIZE (10MB)", "description": "保存文件到 public/uploads/YYYY-MM/cuid.ext,写入 fileAttachments 表,返回 FileUploadResult"}, "/api/files/[id]": {"methods": ["GET", "DELETE"], "handler": "文件元数据查询/删除", "auth": "GET: requireAuth, DELETE: requirePermission(FILE_DELETE)", "module": "files", "description": "GET 返回文件元数据;DELETE 删除 DB 记录并 unlink 磁盘文件(静默失败)"}, "/api/files/batch-delete": {"methods": ["POST"], "handler": "批量删除文件", "auth": "requirePermission(FILE_DELETE)", "module": "files", "validation": "JSON body { ids: string[] },空数组返回 400", "description": "先通过 getFileAttachmentsByIds 查出文件记录,并行调用 storageProvider.delete 删除磁盘文件(静默失败),再调用 deleteFileAttachments 删除 DB 记录(失败时回退到逐条删除);响应 { success, message, deletedCount, failedIds }"}, "/api/search": {"methods": ["GET"], "handler": "全局全文检索", "auth": "requireAuth", "module": "shared.db (questions/textbooks/exams/announcements)", "validation": "query params: q (关键词), type=all|question|textbook|exam|announcement, page=1, pageSize=10 (上限 50)", "description": "并行查询 questions/textbooks/exams/announcements(公告仅 status=published),按 createdAt 降序排序后分页;question content 字段 CAST AS CHAR 模糊匹配;返回 { success, query, type, results: [{ id, title, snippet, type, href, createdAt }], total, page, pageSize }"}, "/api/export": {"methods": ["POST"], "handler": "Excel 导出(grades/users/attendance)", "auth": "requireAuth", "module": "shared.lib.excel + users/grades", "validation": "JSON body { type, params }", "description": "按 type 分发到 exportGradeRecordsToExcel/exportUsersToExcel,返回 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 二进制流"}, "/api/import": {"methods": ["POST"], "handler": "Excel 解析预览(不写 DB)", "auth": "requirePermission(USER_MANAGE)", "module": "shared.lib.excel", "validation": "multipart/form-data file,限 .xlsx/.xls,10MB 上限", "description": "接收 Excel 文件,调用 parseExcel 返回 sheets 预览数据(实际导入由 users/actions.importUsersAction 完成)"} }, "devops": { "ci": { "configFile": ".gitea/workflows/ci.yml", "triggers": ["push to main", "pull_request to main", "schedule cron 0 2 * * *"], "jobs": { "build-deploy": { "runsOn": "CDCD", "container": "dockerreg.eazygame.cn/node-with-docker:22", "trigger": "push/PR to main", "steps": ["checkout", "cache npm", "configure npm proxy", "npm ci", "lint", "typecheck", "install playwright chromium", "integration tests", "e2e tests", "cache next.js build", "build", "prepare standalone", "deploy to docker"] }, "security-audit": { "runsOn": "ubuntu-latest", "trigger": "push/PR to main", "steps": ["checkout", "setup node 20", "npm ci", "npm audit --audit-level=moderate (continue-on-error)", "npm audit --audit-level=critical", "upload audit-report.json artifact"] }, "scheduled-backup": { "runsOn": "ubuntu-latest", "trigger": "schedule cron 0 2 * * *", "condition": "github.event_name == 'schedule'", "steps": ["checkout", "run scripts/backup-db.sh (env DATABASE_URL, BACKUP_DIR)", "upload backups/ artifact (retention 30 days)"] } } }, "scripts": { "scripts/audit.sh": { "type": "bash", "purpose": "依赖安全审计,运行 npm audit --audit-level=moderate,失败时生成 audit-report.json", "platform": "Linux/macOS" }, "scripts/audit.ps1": { "type": "powershell", "purpose": "依赖安全审计(Windows 版本)", "platform": "Windows" }, "scripts/backup-db.sh": { "type": "bash", "purpose": "MySQL 数据库备份,从 DATABASE_URL 解析连接信息,gzip 压缩,保留 RETENTION_DAYS 天(默认 30)", "env": ["DATABASE_URL", "BACKUP_DIR", "RETENTION_DAYS"], "output": "${BACKUP_DIR}/db_backup_${TIMESTAMP}.sql.gz" }, "scripts/restore-db.sh": { "type": "bash", "purpose": "MySQL 数据库恢复,从指定备份文件恢复", "env": ["DATABASE_URL"], "usage": "./restore-db.sh " }, "scripts/test-backup.sh": { "type": "bash", "purpose": "备份流程测试,执行一次备份并验证最新备份文件" } }, "packageJsonScripts": { "audit": "npm audit --audit-level=moderate", "audit:report": "npm audit --json > audit-report.json", "backup": "bash scripts/backup-db.sh", "restore": "bash scripts/restore-db.sh" }, "gitignore": { "added": ["/backups/", "/audit-report.json", "/playwright-report/", "/test-results/"] } }, "testing": { "e2e": { "configFile": "playwright.config.ts", "testDir": "./tests/e2e", "baseURL": "http://127.0.0.1:3000", "webServer": { "command": "npm run dev", "port": 3000, "timeout": 180000, "reuseExistingServer": "!process.env.CI", "env": { "SKIP_ENV_VALIDATION": "1", "NEXTAUTH_SECRET": "test-nextauth-secret", "NEXTAUTH_URL": "http://127.0.0.1:3000", "DATABASE_URL": "mysql://test:test@127.0.0.1:3306/test_db" } }, "projects": [{"name": "chromium", "channel": "CI: undefined, local: chrome"}], "retries": "CI: 2, local: 0", "workers": "CI: 2, local: default", "testFiles": { "smoke-auth.spec.ts": {"coverage": "登录/注册页面控件渲染冒烟测试", "requiresDb": false}, "auth-business-flow.spec.ts": {"coverage": "注册→登录→访问受保护区域完整流程", "requiresDb": true}, "full-route-regression.spec.ts": {"coverage": "全路由清单完整性 + 公开/受保护路由守卫", "requiresDb": false}, "auth.spec.ts": {"coverage": "认证页面(登录/注册/隐私/协议)渲染 + 未认证重定向", "requiresDb": false}, "navigation.spec.ts": {"coverage": "admin/teacher/student 导航链接无 404", "requiresDb": true, "envVars": ["E2E_ADMIN_EMAIL", "E2E_TEACHER_EMAIL", "E2E_STUDENT_EMAIL"]}, "announcements.spec.ts": {"coverage": "公告页面未认证重定向 + 登录后渲染", "requiresDb": "partial"}, "grades.spec.ts": {"coverage": "成绩页面未认证重定向 + 登录后渲染", "requiresDb": "partial"} } } } }