Files
NextEdu/docs/architecture/005_architecture_data.json
SpecialX b86255f0ea feat(P2): 实现选课管理、考试监考、学情诊断三大功能模块
## 新增功能模块

### 1. 选课管理(elective)
- 新增表:electiveCourses、courseSelections
- 新增权限:ELECTIVE_MANAGE/ELECTIVE_READ/ELECTIVE_SELECT
- 支持先到先得 + 抽签两种选课模式
- admin/teacher/student 三端页面

### 2. 考试监考(proctoring)
- exams 表扩展:examMode/durationMinutes/antiCheatEnabled 等字段
- 新增表:examProctoringEvents
- 新增权限:EXAM_PROCTOR/EXAM_PROCTOR_READ
- 教师监考面板 + 学生端防作弊监控
- API:/api/proctoring/event 接收事件上报

### 3. 学情诊断报告(diagnostic)
- 新增表:knowledgePointMastery、learningDiagnosticReports
- 新增权限:DIAGNOSTIC_MANAGE/DIAGNOSTIC_READ
- 基于提交答案自动计算知识点掌握度
- 生成个人/班级诊断报告(强项/弱项/建议)
- 雷达图可视化

## 其他改动
- 项目规则:单文件行数限制从 300 行调整为企业级规范(组件≤500/Actions≤800/硬上限1000)
- scripts/seed.ts:消除全部 any 类型,定义内部类型,0 lint 错误
- 架构文档 004/005 同步更新三个新模块
- 迁移文件 0001_heavy_sage.sql 生成

## 验证
- npx tsc --noEmit:0 错误
- npm run lint:0 错误 0 警告
2026-06-17 19:12:51 +08:00

1909 lines
259 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"_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<boolean>",
"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<boolean>",
"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<AuthContext>",
"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<AuthContext>",
"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<AuthContext>",
"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<void>",
"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<void>",
"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<Buffer>",
"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<ParsedSheet[]>",
"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<Buffer>",
"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<T>(): { isPending: boolean; execute: (action: () => Promise<ActionState<T>>) => void }",
"purpose": "包装Server Action + toast反馈"
},
{
"name": "useDebounce",
"file": "hooks/use-debounce.ts",
"signature": "useDebounce<T>(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<T>(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<void>",
"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<string>; read(storagePath: string): Promise<Buffer>; delete(storagePath: string): Promise<void>; exists(storagePath: string): Promise<boolean>; 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/searchCmd/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<T = void> = { success: boolean; message?: string; errors?: Record<string, string[]>; 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+knowledgePointIdonDuplicateKeyUpdate upsert"},
"learningDiagnosticReports": {"fields": ["id","studentId","generatedBy","reportType","period","summary","strengths","weaknesses","recommendations","overallScore","status","createdAt","updatedAt"], "usedBy": ["diagnostic"], "description": "学情诊断报告reportType: individual/class/gradestatus: 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/cancelledselectionMode: fcfs/lottery"},
"courseSelections": {"fields": ["id","courseId","studentId","status","priority","selectedAt","enrolledAt","droppedAt","lotteryRank","createdAt","updatedAt"], "usedBy": ["elective"], "description": "选课记录(复合主键 courseId+studentIdstatus: selected/enrolled/waitlist/dropped/rejected"}
}
},
"auth": {
"path": "src/auth.ts",
"description": "用户认证NextAuth配置、JWT/Session callbacks、events回调(登录日志)、middleware。集成密码安全策略账户锁定、失败登录追踪和登录速率限制",
"exports": {
"functions": [
{"name": "auth", "signature": "auth(): Promise<Session | null>", "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<NextResponse>",
"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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<AiPreviewData> | null, formData: FormData) => Promise<ActionState<AiPreviewData>>", "purpose": "AI预览试卷(不持久化)", "deps": ["requirePermission","ai-pipeline.generateAiPreviewData"], "usedBy": ["exam-ai-generator.tsx"]},
{"name": "regenerateAiQuestionAction", "permission": "EXAM_AI_GENERATE", "signature": "(prevState: ActionState<AiRewriteQuestionData> | null, formData: FormData) => Promise<ActionState<AiRewriteQuestionData>>", "purpose": "AI重写单个题目", "deps": ["requirePermission","ai-pipeline.regenerateAiQuestionByInstruction"], "usedBy": ["exam-preview-question-editor.tsx"]},
{"name": "updateExamAction", "permission": "EXAM_UPDATE", "signature": "(prevState: ActionState<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<ActionState<{ structure: unknown; questions: Array<{ id: string }> }>>", "purpose": "获取考试预览数据", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-viewer.tsx"]},
{"name": "getSubjectsAction", "permission": "EXAM_READ", "signature": "() => Promise<ActionState<{id:string;name:string}[]>>", "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<Exam[]>", "purpose": "查询考试列表(含数据权限过滤)", "usedBy": ["teacher/exams/all/page.tsx", "homework创建页面"]},
{"name": "getExamById", "signature": "getExamById(id: string, scope?: DataScope): Promise<Exam | null>", "purpose": "按ID获取考试详情", "usedBy": ["exam详情/编辑页面"]},
{"name": "persistExamDraft", "signature": "persistExamDraft(input: { examId, title, creatorId, subjectId, gradeId, scheduledAt?, description }): Promise<void>", "purpose": "持久化手动考试草稿", "usedBy": ["createExamAction"]},
{"name": "persistAiGeneratedExamDraft", "signature": "persistAiGeneratedExamDraft(input: { examId, title, creatorId, subjectId, gradeId, scheduledAt?, description, structure, generated }): Promise<void>", "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<AiDraftResult>", "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<ExamFormValues>) => { 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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<TeacherGradeTrendItem[]>", "usedBy": ["dashboard (教师仪表盘)"]},
{"name": "getHomeworkAssignments", "signature": "(params?: { creatorId?, ids?, classId?, scope? }) => Promise<HomeworkAssignmentListItem[]>", "usedBy": ["teacher作业列表页", "homework-assignment-form.tsx"]},
{"name": "getHomeworkAssignmentReviewList", "signature": "(params: { creatorId: string; scope? }) => Promise<HomeworkAssignmentReviewListItem[]>", "usedBy": ["teacher批改列表"]},
{"name": "getHomeworkSubmissions", "signature": "(params?: { assignmentId?, classId?, creatorId?, scope? }) => Promise<HomeworkSubmissionListItem[]>", "usedBy": ["teacher提交列表"]},
{"name": "getStudentHomeworkAssignments", "signature": "(studentId: string) => Promise<StudentHomeworkAssignmentListItem[]>", "usedBy": ["student/dashboard"]},
{"name": "getStudentDashboardGrades", "signature": "(studentId: string) => Promise<StudentDashboardGradeProps>", "usedBy": ["dashboard/data-access.ts"]},
{"name": "getHomeworkAssignmentAnalytics", "signature": "(assignmentId: string) => Promise<HomeworkAssignmentAnalytics | null>", "usedBy": ["homework错误分析组件"]},
{"name": "getHomeworkAssignmentById", "signature": "(id: string, scope?: DataScope) => Promise<...>", "purpose": "按ID获取作业详情", "usedBy": ["homework详情页"]},
{"name": "getHomeworkSubmissionDetails", "signature": "(submissionId: string) => Promise<HomeworkSubmissionDetails | null>", "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<StudentHomeworkTakeData | null>", "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<typeof CreateHomeworkAssignmentSchema>", "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<string> | undefined, formData: FormData | CreateQuestionInput) => Promise<ActionState<string>>", "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<KnowledgePointOption[]>", "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<typeof CreateQuestionSchema>", "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<typeof QuestionTypeEnum>", "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<ActionState>", "purpose": "创建教材"},
{"name": "updateTextbookAction", "permission": "TEXTBOOK_UPDATE", "signature": "(textbookId, prevState, formData) => Promise<ActionState>", "purpose": "更新教材元信息"},
{"name": "deleteTextbookAction", "permission": "TEXTBOOK_DELETE", "signature": "(textbookId) => Promise<ActionState>", "purpose": "删除教材"},
{"name": "createChapterAction", "permission": "TEXTBOOK_CREATE", "signature": "(textbookId, parentId?, prevState, formData) => Promise<ActionState>", "purpose": "创建章节"},
{"name": "updateChapterContentAction", "permission": "TEXTBOOK_UPDATE", "signature": "(chapterId, content, textbookId) => Promise<ActionState>", "purpose": "更新章节内容(Markdown)"},
{"name": "deleteChapterAction", "permission": "TEXTBOOK_DELETE", "signature": "(chapterId, textbookId) => Promise<ActionState>", "purpose": "删除章节"},
{"name": "createKnowledgePointAction", "permission": "TEXTBOOK_CREATE", "signature": "(chapterId, textbookId, prevState, formData) => Promise<ActionState>", "purpose": "创建知识点"},
{"name": "updateKnowledgePointAction", "permission": "TEXTBOOK_UPDATE", "signature": "(kpId, textbookId, prevState, formData) => Promise<ActionState>", "purpose": "更新知识点"},
{"name": "deleteKnowledgePointAction", "permission": "TEXTBOOK_DELETE", "signature": "(kpId, textbookId) => Promise<ActionState>", "purpose": "删除知识点"},
{"name": "reorderChaptersAction", "permission": "TEXTBOOK_UPDATE", "signature": "(chapterId, newIndex, parentId, textbookId) => Promise<ActionState>", "purpose": "章节排序"}
],
"dataAccess": [
{"name": "getTextbooks", "signature": "(query?, subject?, grade?) => Promise<Textbook[]>", "usedBy": ["teacher/textbooks/page.tsx"]},
{"name": "getTextbookById", "signature": "(id) => Promise<Textbook | undefined>", "usedBy": ["teacher/textbooks/[id]/page.tsx"]},
{"name": "getChaptersByTextbookId", "signature": "(textbookId) => Promise<Chapter[]>", "usedBy": ["textbook-reader.tsx"]},
{"name": "getKnowledgePointsByChapterId", "signature": "(chapterId) => Promise<KnowledgePoint[]>", "usedBy": ["textbook-reader.tsx"]},
{"name": "getKnowledgePointsByTextbookId", "signature": "(textbookId) => Promise<KnowledgePoint[]>", "usedBy": ["textbook-reader.tsx"]},
{"name": "createTextbook", "signature": "(input: CreateTextbookInput) => Promise<Textbook>", "purpose": "创建教材", "usedBy": ["createTextbookAction"]},
{"name": "updateTextbook", "signature": "(id: string, input: UpdateTextbookInput) => Promise<void>", "purpose": "更新教材", "usedBy": ["updateTextbookAction"]},
{"name": "deleteTextbook", "signature": "(id: string) => Promise<void>", "purpose": "删除教材", "usedBy": ["deleteTextbookAction"]},
{"name": "createChapter", "signature": "(input: CreateChapterInput) => Promise<Chapter>", "purpose": "创建章节", "usedBy": ["createChapterAction"]},
{"name": "updateChapterContent", "signature": "(input: UpdateChapterContentInput) => Promise<void>", "purpose": "更新章节内容", "usedBy": ["updateChapterContentAction"]},
{"name": "deleteChapter", "signature": "(chapterId: string, textbookId: string) => Promise<void>", "purpose": "删除章节", "usedBy": ["deleteChapterAction"]},
{"name": "createKnowledgePoint", "signature": "(input: CreateKnowledgePointInput) => Promise<KnowledgePoint>", "purpose": "创建知识点", "usedBy": ["createKnowledgePointAction"]},
{"name": "updateKnowledgePoint", "signature": "(input: UpdateKnowledgePointInput) => Promise<void>", "purpose": "更新知识点", "usedBy": ["updateKnowledgePointAction"]},
{"name": "deleteKnowledgePoint", "signature": "(kpId: string, textbookId: string) => Promise<void>", "purpose": "删除知识点", "usedBy": ["deleteKnowledgePointAction"]},
{"name": "reorderChapters", "signature": "(chapterId: string, newIndex: number, parentId: string | null, textbookId: string) => Promise<void>", "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<ActionState<string>>", "purpose": "教师创建班级"},
{"name": "updateTeacherClassAction", "permission": "CLASS_UPDATE", "signature": "(classId, prevState, formData) => Promise<ActionState>", "purpose": "教师更新班级"},
{"name": "deleteTeacherClassAction", "permission": "CLASS_DELETE", "signature": "(classId) => Promise<ActionState>", "purpose": "教师删除班级"},
{"name": "createGradeClassAction", "permission": "CLASS_CREATE", "signature": "(prevState, formData) => Promise<ActionState<string>>", "purpose": "年级主任创建班级"},
{"name": "updateGradeClassAction", "permission": "CLASS_UPDATE", "signature": "(classId, prevState, formData) => Promise<ActionState>", "purpose": "年级主任更新班级"},
{"name": "deleteGradeClassAction", "permission": "CLASS_DELETE", "signature": "(classId) => Promise<ActionState>", "purpose": "年级主任删除班级"},
{"name": "enrollStudentByEmailAction", "permission": "CLASS_ENROLL", "signature": "(classId, prevState, formData) => Promise<ActionState>", "purpose": "通过邮箱注册学生"},
{"name": "joinClassByInvitationCodeAction", "permission": "CLASS_ENROLL", "signature": "(prevState, formData) => Promise<ActionState<{classId:string}>>", "purpose": "通过邀请码加入"},
{"name": "ensureClassInvitationCodeAction", "permission": "CLASS_ENROLL", "signature": "(classId) => Promise<ActionState<{code:string}>>", "purpose": "确保邀请码存在"},
{"name": "regenerateClassInvitationCodeAction", "permission": "CLASS_ENROLL", "signature": "(classId) => Promise<ActionState<{code:string}>>", "purpose": "重新生成邀请码"},
{"name": "setStudentEnrollmentStatusAction", "permission": "CLASS_ENROLL", "signature": "(classId, studentId, status) => Promise<ActionState>", "purpose": "设置学生状态"},
{"name": "createClassScheduleItemAction", "permission": "CLASS_SCHEDULE", "signature": "(prevState, formData) => Promise<ActionState<string>>", "purpose": "创建课表项"},
{"name": "updateClassScheduleItemAction", "permission": "CLASS_SCHEDULE", "signature": "(scheduleId, prevState, formData) => Promise<ActionState>", "purpose": "更新课表项"},
{"name": "deleteClassScheduleItemAction", "permission": "CLASS_SCHEDULE", "signature": "(scheduleId) => Promise<ActionState>", "purpose": "删除课表项"},
{"name": "createAdminClassAction", "permission": "CLASS_CREATE", "signature": "(prevState, formData) => Promise<ActionState<string>>", "purpose": "管理员创建班级"},
{"name": "updateAdminClassAction", "permission": "CLASS_UPDATE", "signature": "(classId, prevState, formData) => Promise<ActionState>", "purpose": "管理员更新班级"},
{"name": "deleteAdminClassAction", "permission": "CLASS_DELETE", "signature": "(classId) => Promise<ActionState>", "purpose": "管理员删除班级"}
],
"dataAccess": [
{"name": "getTeacherClasses", "signature": "(params?: { teacherId?: string }) => Promise<TeacherClass[]>", "usedBy": ["teacher/classes/my", "dashboard"]},
{"name": "getAdminClasses", "signature": "() => Promise<AdminClassListItem[]>", "usedBy": ["admin班级管理"]},
{"name": "getGradeManagedClasses", "signature": "(userId) => Promise<AdminClassListItem[]>", "usedBy": ["grade_head班级管理"]},
{"name": "getStudentClasses", "signature": "(studentId) => Promise<StudentEnrolledClass[]>", "usedBy": ["student/dashboard"]},
{"name": "getStudentSchedule", "signature": "(studentId) => Promise<StudentScheduleItem[]>", "usedBy": ["student课表"]},
{"name": "getClassStudents", "signature": "(params?: { classId?, q?, status?, teacherId? }) => Promise<ClassStudent[]>", "usedBy": ["teacher/classes/students"]},
{"name": "getClassSchedule", "signature": "(params?: { classId?, teacherId? }) => Promise<ClassScheduleItem[]>", "usedBy": ["teacher/classes/schedule"]},
{"name": "getClassHomeworkInsights", "signature": "(params: { classId, teacherId?, limit? }) => Promise<ClassHomeworkInsights | null>", "usedBy": ["classes作业洞察"]},
{"name": "getGradeHomeworkInsights", "signature": "(params: { gradeId, limit? }) => Promise<GradeHomeworkInsights | null>", "usedBy": ["年级作业洞察"]},
{"name": "getTeacherIdForMutations", "signature": "() => Promise<string>", "purpose": "获取当前教师ID(用于写操作)", "usedBy": ["classes写操作内部"]},
{"name": "getClassSubjects", "signature": "(classId: string) => Promise<ClassSubject[]>", "purpose": "获取班级学科列表", "usedBy": ["class-detail组件"]},
{"name": "getTeacherOptions", "signature": "() => Promise<TeacherOption[]>", "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<string>", "purpose": "教师创建班级", "usedBy": ["createTeacherClassAction"]},
{"name": "createAdminClass", "signature": "(input) => Promise<string>", "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<void>", "purpose": "教师更新班级", "usedBy": ["updateTeacherClassAction"]},
{"name": "updateAdminClass", "signature": "(classId: string, input) => Promise<void>", "purpose": "管理员更新班级", "usedBy": ["updateAdminClassAction"]},
{"name": "setClassSubjectTeachers", "signature": "(classId: string, assignments: ClassSubjectTeacherAssignment[]) => Promise<void>", "purpose": "设置班级学科教师", "usedBy": ["classes内部"]},
{"name": "deleteTeacherClass", "signature": "(classId: string) => Promise<void>", "purpose": "教师删除班级", "usedBy": ["deleteTeacherClassAction"]},
{"name": "deleteAdminClass", "signature": "(classId: string) => Promise<void>", "purpose": "管理员删除班级", "usedBy": ["deleteAdminClassAction"]},
{"name": "enrollStudentByEmail", "signature": "(classId: string, email: string) => Promise<void>", "purpose": "通过邮箱注册学生", "usedBy": ["enrollStudentByEmailAction"]},
{"name": "setStudentEnrollmentStatus", "signature": "(classId: string, studentId: string, status: string) => Promise<void>", "purpose": "设置学生状态", "usedBy": ["setStudentEnrollmentStatusAction"]},
{"name": "createClassScheduleItem", "signature": "(input: CreateClassScheduleItemInput) => Promise<string>", "purpose": "创建课表项", "usedBy": ["createClassScheduleItemAction"]},
{"name": "updateClassScheduleItem", "signature": "(scheduleId: string, input: UpdateClassScheduleItemInput) => Promise<void>", "purpose": "更新课表项", "usedBy": ["updateClassScheduleItemAction"]},
{"name": "deleteClassScheduleItem", "signature": "(scheduleId: string) => Promise<void>", "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<ActionState<string>>", "purpose": "创建学校", "auditLog": "school.create"},
{"name": "updateSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(schoolId, prevState, formData) => Promise<ActionState<string>>", "purpose": "更新学校", "auditLog": "school.update"},
{"name": "deleteSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(schoolId) => Promise<ActionState<string>>", "purpose": "删除学校", "auditLog": "school.delete"},
{"name": "createGradeAction", "permission": "GRADE_MANAGE", "signature": "(prevState, formData) => Promise<ActionState<string>>", "purpose": "创建年级"},
{"name": "updateGradeAction", "permission": "GRADE_MANAGE", "signature": "(gradeId, prevState, formData) => Promise<ActionState<string>>", "purpose": "更新年级"},
{"name": "deleteGradeAction", "permission": "GRADE_MANAGE", "signature": "(gradeId) => Promise<ActionState<string>>", "purpose": "删除年级"},
{"name": "createDepartmentAction", "permission": "SCHOOL_MANAGE", "signature": "(prevState, formData) => Promise<ActionState<string>>", "purpose": "创建部门"},
{"name": "updateDepartmentAction", "permission": "SCHOOL_MANAGE", "signature": "(departmentId, prevState, formData) => Promise<ActionState<string>>", "purpose": "更新部门"},
{"name": "deleteDepartmentAction", "permission": "SCHOOL_MANAGE", "signature": "(departmentId) => Promise<ActionState<string>>", "purpose": "删除部门"},
{"name": "createAcademicYearAction", "permission": "SCHOOL_MANAGE", "signature": "(prevState, formData) => Promise<ActionState<string>>", "purpose": "创建学年"},
{"name": "updateAcademicYearAction", "permission": "SCHOOL_MANAGE", "signature": "(academicYearId, prevState, formData) => Promise<ActionState<string>>", "purpose": "更新学年"},
{"name": "deleteAcademicYearAction", "permission": "SCHOOL_MANAGE", "signature": "(academicYearId) => Promise<ActionState<string>>", "purpose": "删除学年"}
],
"dataAccess": [
{"name": "getSchools", "signature": "() => Promise<SchoolListItem[]>", "usedBy": ["admin学校管理", "onboarding"]},
{"name": "getGrades", "signature": "() => Promise<GradeListItem[]>", "usedBy": ["admin年级管理", "exams", "onboarding"]},
{"name": "getDepartments", "signature": "() => Promise<DepartmentListItem[]>", "usedBy": ["admin部门管理"]},
{"name": "getAcademicYears", "signature": "() => Promise<AcademicYearListItem[]>", "usedBy": ["admin学年管理"]},
{"name": "getStaffOptions", "signature": "() => Promise<StaffOption[]>", "usedBy": ["school组件"]},
{"name": "getGradesForStaff", "signature": "(staffId) => Promise<GradeListItem[]>", "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<AdminDashboardData>", "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<Role, NavItem[]>", "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<AiProviderSummary[]>", "purpose": "获取AI Provider列表"},
{"name": "upsertAiProviderAction", "permission": "AI_CONFIGURE", "signature": "(data) => Promise<ActionState<string>>", "purpose": "创建/更新AI Provider", "deps": ["shared/lib/ai (encrypt/decrypt)"]},
{"name": "testAiProviderAction", "permission": "AI_CONFIGURE", "signature": "(data) => Promise<ActionState<null>>", "purpose": "测试AI Provider连通性", "deps": ["shared/lib/ai.testAiProviderConfig"]},
{"name": "changePasswordAction", "file": "actions-password.ts", "permission": "requireAuth()", "signature": "(prevState: ActionState<null>, formData: FormData) => Promise<ActionState<null>>", "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 tabSecurity 含 PasswordChangeFormNotifications 含 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<void>", "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<ActionState<string>>", "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<UserImportResult> | null, formData: FormData) => Promise<ActionState<UserImportResult>>", "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<ActionState<{ buffer: string; filename: string }>>", "file": "actions.ts", "permission": "USER_MANAGE", "purpose": "导出用户列表(返回 base64 编码的 Excel", "deps": ["requirePermission", "import-export.exportUsersToExcel"], "usedBy": ["待扩展"] }
],
"dataAccess": [
{ "name": "getUserProfile", "signature": "(userId: string) => Promise<UserProfile | null>", "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<Buffer>", "file": "import-export.ts", "purpose": "生成用户导入模板(列:姓名/邮箱/角色/手机/班级邀请码,含示例行)", "deps": ["shared.lib.excel.generateTemplate"], "usedBy": ["actions.downloadUserTemplateAction"] },
{ "name": "parseUserImportData", "signature": "(rows: Record<string, unknown>[]) => UserImportValidation", "file": "import-export.ts", "purpose": "解析并验证导入行(校验姓名/邮箱格式/角色枚举/邀请码仅 student", "deps": [], "usedBy": ["actions.importUsersAction"] },
{ "name": "batchImportUsers", "signature": "(records: UserImportRecord[]) => Promise<UserImportResult>", "file": "import-export.ts", "purpose": "批量创建用户(默认密码 123456 bcrypt 哈希,自动创建 usersToRolesstudent 通过邀请码自动加入班级)", "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<Buffer>", "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<PaginatedResult<AuditLog>>", "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<PaginatedResult<LoginLog>>", "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<string[]>", "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<PaginatedResult<DataChangeLog>>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.dataChangeLogs"], "usedBy": ["getDataChangeLogsAction"] },
{ "name": "getDataChangeStats", "signature": "() => Promise<DataChangeStat[]>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.dataChangeLogs"], "usedBy": ["getDataChangeLogsAction"] },
{ "name": "getDataChangeTableOptions", "signature": "() => Promise<string[]>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.dataChangeLogs"], "usedBy": ["getDataChangeLogsAction"] },
{ "name": "getDataChangeLogsForExport", "signature": "(params?: DataChangeLogQueryParams) => Promise<DataChangeLog[]>", "file": "data-access.ts", "deps": ["getDataChangeLogs"], "usedBy": ["exportDataChangeLogsAction"] },
{ "name": "getAuditLogsForExport", "signature": "(params?: AuditLogQueryParams) => Promise<AuditLog[]>", "file": "data-access.ts", "deps": ["getAuditLogs"], "usedBy": ["exportAuditLogsAction"] },
{ "name": "getLoginLogsForExport", "signature": "(params?: LoginLogQueryParams) => Promise<LoginLog[]>", "file": "data-access.ts", "deps": ["getLoginLogs"], "usedBy": ["exportLoginLogsAction"] }
],
"actions": [
{ "name": "getDataChangeLogsAction", "permission": "AUDIT_LOG_READ", "signature": "(params?: DataChangeLogQueryParams) => Promise<ActionState<{ items, total, page, pageSize, totalPages, tableOptions, stats }>>", "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<ActionState<{ buffer: Buffer; filename: string }>>", "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<ActionState<{ buffer: Buffer; filename: string }>>", "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<ActionState<{ buffer: Buffer; filename: string }>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "purpose": "创建公告(草稿/已发布)", "deps": ["requirePermission", "shared/db"], "usedBy": ["announcement-form.tsx"] },
{ "name": "updateAnnouncementAction", "permission": "ANNOUNCEMENT_MANAGE", "signature": "(id: string, prevState: ActionState<string> | null, formData: FormData) => Promise<ActionState<string>>", "purpose": "更新公告", "deps": ["requirePermission", "shared/db"], "usedBy": ["announcement-form.tsx"] },
{ "name": "deleteAnnouncementAction", "permission": "ANNOUNCEMENT_MANAGE", "signature": "(id: string) => Promise<ActionState<string>>", "purpose": "删除公告", "deps": ["requirePermission", "shared/db"], "usedBy": ["announcement-detail.tsx"] },
{ "name": "publishAnnouncementAction", "permission": "ANNOUNCEMENT_MANAGE", "signature": "(id: string) => Promise<ActionState<string>>", "purpose": "发布公告", "deps": ["requirePermission", "shared/db"], "usedBy": ["announcement-detail.tsx"] },
{ "name": "archiveAnnouncementAction", "permission": "ANNOUNCEMENT_MANAGE", "signature": "(id: string) => Promise<ActionState<string>>", "purpose": "归档公告", "deps": ["requirePermission", "shared/db"], "usedBy": ["announcement-detail.tsx"] },
{ "name": "getAnnouncementsAction", "permission": "requireAuth", "signature": "(params?: GetAnnouncementsParams) => Promise<ActionState<Announcement[]>>", "purpose": "获取公告列表(所有登录用户可读)", "deps": ["requireAuth", "data-access.getAnnouncements"], "usedBy": ["待扩展"] }
],
"dataAccess": [
{ "name": "getAnnouncements", "signature": "(params?: { status?, type?, page?, pageSize? }) => Promise<Announcement[]>", "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<Announcement | null>", "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<FileAttachment | null>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["app/api/upload/route.ts"] },
{ "name": "getFileAttachment", "signature": "(id: string) => Promise<FileAttachment | null>", "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<FileAttachment[]>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["按关联资源查询文件列表"] },
{ "name": "getFileAttachmentsByUploader", "signature": "(uploaderId: string) => Promise<FileAttachment[]>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["按上传者查询文件列表"] },
{ "name": "getAllFileAttachments", "signature": "(limit?: number) => Promise<FileAttachment[]>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["app/(dashboard)/admin/files/page.tsx"] },
{ "name": "deleteFileAttachment", "signature": "(id: string) => Promise<boolean>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.fileAttachments"], "usedBy": ["app/api/files/[id]/route.ts"] },
{ "name": "deleteFileAttachments", "signature": "(ids: string[]) => Promise<BatchDeleteResult>", "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<FileAttachment[]>", "file": "data-access.ts", "purpose": "按 mimeType精确或前缀匹配与 searchoriginalName/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<FileStats>", "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<FileAttachment[]>", "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<GradeRecordListItem[]>", "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<GradeRecord | null>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/actions.getGradeRecordByIdAction"] },
{ "name": "createGradeRecord", "signature": "(data: CreateGradeRecordInput, recordedBy: string) => Promise<string>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/actions.createGradeRecordAction"] },
{ "name": "batchCreateGradeRecords", "signature": "(data: BatchCreateGradeRecordInput, recordedBy: string) => Promise<number>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/actions.batchCreateGradeRecordsAction"] },
{ "name": "updateGradeRecord", "signature": "(id: string, data: UpdateGradeRecordInput) => Promise<boolean>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.gradeRecords"], "usedBy": ["grades/actions.updateGradeRecordAction"] },
{ "name": "deleteGradeRecord", "signature": "(id: string) => Promise<boolean>", "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<GradeStats>", "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<ClassGradeStats>", "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<StudentGradeSummary>", "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<ClassRankingItem[]>", "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<GradeTrendResult>", "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<ClassComparisonItem[]>", "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<SubjectComparisonItem[]>", "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<GradeDistributionResult>", "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<RankingTrendResult | null>", "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<ActionState<string>>", "file": "actions.ts", "permission": "GRADE_RECORD_MANAGE", "usedBy": ["grades/components/grade-record-form"] },
{ "name": "batchCreateGradeRecordsAction", "signature": "(prevState, formData) => Promise<ActionState<number>>", "file": "actions.ts", "permission": "GRADE_RECORD_MANAGE", "usedBy": ["grades/components/batch-grade-entry"] },
{ "name": "updateGradeRecordAction", "signature": "(prevState, formData) => Promise<ActionState<string>>", "file": "actions.ts", "permission": "GRADE_RECORD_MANAGE", "usedBy": ["grades/components/grade-record-list"] },
{ "name": "deleteGradeRecordAction", "signature": "(prevState, formData) => Promise<ActionState<string>>", "file": "actions.ts", "permission": "GRADE_RECORD_MANAGE", "usedBy": ["grades/components/grade-record-list"] },
{ "name": "getGradeRecordsAction", "signature": "(params) => Promise<GradeRecordListItem[]>", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "usedBy": ["teacher/grades/page"] },
{ "name": "getClassGradeStatsAction", "signature": "(classId, subjectId?, examId?) => Promise<ClassGradeStats>", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "usedBy": ["teacher/grades/stats/page"] },
{ "name": "getStudentGradeSummaryAction", "signature": "(studentId?) => Promise<StudentGradeSummary>", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "usedBy": ["student/grades/page", "parent/grades/page"] },
{ "name": "getClassRankingAction", "signature": "(classId, subjectId?, examId?) => Promise<ClassRankingItem[]>", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "usedBy": ["teacher/grades/stats/page"] },
{ "name": "getGradeRecordByIdAction", "signature": "(id) => Promise<GradeRecord | null>", "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<ActionState<{ buffer: string; filename: string }>>", "file": "actions.ts", "permission": "GRADE_RECORD_READ", "purpose": "导出成绩到 Exceldetail=成绩明细+统计汇总class=班级多科目横向对比总表),返回 base64 buffer", "deps": ["requirePermission", "export.exportGradeRecordsToExcel", "export.exportClassGradeReportToExcel", "export.formatDateForFile"], "usedBy": ["grades/components/export-button.tsx"] },
{ "name": "getGradeTrendAction", "signature": "(params) => Promise<GradeTrendResult>", "file": "actions-analytics.ts", "permission": "GRADE_RECORD_READ", "purpose": "获取成绩趋势(按学生/科目/学期,返回归一化分数趋势点)", "usedBy": ["teacher/grades/analytics"] },
{ "name": "getClassComparisonAction", "signature": "(params) => Promise<ClassComparisonItem[]>", "file": "actions-analytics.ts", "permission": "GRADE_RECORD_READ", "purpose": "获取班级对比(同年级各班的均分/及格率/优秀率)", "usedBy": ["teacher/grades/analytics"] },
{ "name": "getSubjectComparisonAction", "signature": "(params) => Promise<SubjectComparisonItem[]>", "file": "actions-analytics.ts", "permission": "GRADE_RECORD_READ", "purpose": "获取科目对比(同班级各科目雷达图数据)", "usedBy": ["teacher/grades/analytics"] },
{ "name": "getGradeDistributionAction", "signature": "(params) => Promise<GradeDistributionResult>", "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<RankingTrendResult | null>", "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<Buffer>", "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<Buffer>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "purpose": "创建课程计划", "deps": ["requirePermission", "shared/db", "data-access.createCoursePlan"], "usedBy": ["course-plan-form.tsx"] },
{ "name": "updateCoursePlanAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(id: string, prevState: ActionState<string> | null, formData: FormData) => Promise<ActionState<string>>", "purpose": "更新课程计划", "deps": ["requirePermission", "shared/db", "data-access.updateCoursePlan"], "usedBy": ["course-plan-form.tsx"] },
{ "name": "deleteCoursePlanAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(id: string) => Promise<ActionState<string>>", "purpose": "删除课程计划", "deps": ["requirePermission", "shared/db", "data-access.deleteCoursePlan"], "usedBy": ["course-plan-detail.tsx"] },
{ "name": "getCoursePlansAction", "permission": "COURSE_PLAN_READ", "signature": "(params?: GetCoursePlansParams) => Promise<ActionState<CoursePlanListItem[]>>", "purpose": "获取课程计划列表", "deps": ["requirePermission", "data-access.getCoursePlans"], "usedBy": ["待扩展"] },
{ "name": "getCoursePlanAction", "permission": "COURSE_PLAN_READ", "signature": "(id: string) => Promise<ActionState<CoursePlanWithItems>>", "purpose": "获取课程计划详情(含周计划条目)", "deps": ["requirePermission", "data-access.getCoursePlanById"], "usedBy": ["待扩展"] },
{ "name": "createCoursePlanItemAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(prevState: ActionState<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "purpose": "更新周计划条目", "deps": ["requirePermission", "shared/db", "data-access.updateCoursePlanItem"], "usedBy": ["course-plan-item-editor.tsx"] },
{ "name": "deleteCoursePlanItemAction", "permission": "COURSE_PLAN_MANAGE", "signature": "(id: string) => Promise<ActionState<string>>", "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<ActionState<string>>", "purpose": "切换周计划条目完成状态", "deps": ["requirePermission", "shared/db", "data-access.updateCoursePlanItem"], "usedBy": ["course-plan-detail.tsx"] }
],
"dataAccess": [
{ "name": "getCoursePlans", "signature": "(params?: GetCoursePlansParams) => Promise<CoursePlanListItem[]>", "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<CoursePlanWithItems | null>", "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<string>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlans", "@paralleldrive/cuid2"], "usedBy": ["createCoursePlanAction"] },
{ "name": "updateCoursePlan", "signature": "(id: string, data: Partial<UpdateCoursePlanInput>) => Promise<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlans"], "usedBy": ["updateCoursePlanAction"] },
{ "name": "deleteCoursePlan", "signature": "(id: string) => Promise<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlans"], "usedBy": ["deleteCoursePlanAction"] },
{ "name": "createCoursePlanItem", "signature": "(data: CreateCoursePlanItemInput) => Promise<string>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlanItems", "@paralleldrive/cuid2"], "usedBy": ["createCoursePlanItemAction"] },
{ "name": "updateCoursePlanItem", "signature": "(id: string, data: Partial<UpdateCoursePlanItemInput>) => Promise<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlanItems"], "usedBy": ["updateCoursePlanItemAction", "toggleCoursePlanItemCompletedAction"] },
{ "name": "deleteCoursePlanItem", "signature": "(id: string) => Promise<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.coursePlanItems"], "usedBy": ["deleteCoursePlanItemAction"] },
{ "name": "reorderCoursePlanItems", "signature": "(planId: string, items: ReorderCoursePlanItemInput[]) => Promise<void>", "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<ParentChildRelation[]>", "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<ChildBasicInfo | null>", "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<ChildDashboardData | null>", "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<ParentDashboardData>", "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/gradeSiteHeader 通知下拉菜单展示未读数",
"exports": {
"actions": [
{ "name": "sendMessageAction", "permission": "MESSAGE_SEND", "signature": "(prevState: ActionState<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<ActionState<void>>", "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<ActionState<void>>", "purpose": "删除消息(仅发送者或接收者可删)", "deps": ["requirePermission", "data-access.deleteMessage", "revalidatePath"], "usedBy": ["message-detail.tsx"] },
{ "name": "getMessagesAction", "permission": "MESSAGE_READ", "signature": "(params?: { type?, page?, pageSize? }) => Promise<ActionState<PaginatedResult<MessageListItem>>>", "purpose": "获取消息列表(收件箱/已发送,分页)", "deps": ["requirePermission", "data-access.getMessages"], "usedBy": ["message-list.tsx"] },
{ "name": "getMessageDetailAction", "permission": "MESSAGE_READ", "signature": "(id: string) => Promise<ActionState<Message>>", "purpose": "获取消息详情(含回复线程)", "deps": ["requirePermission", "data-access.getMessageById", "data-access.getMessageThread"], "usedBy": ["message-detail.tsx"] },
{ "name": "getRecipientsAction", "permission": "MESSAGE_SEND", "signature": "() => Promise<ActionState<RecipientOption[]>>", "purpose": "获取可发送对象列表(按 DataScope 过滤)", "deps": ["requirePermission", "data-access.getRecipients"], "usedBy": ["messages/compose/page.tsx"] },
{ "name": "getNotificationsAction", "permission": "requireAuth", "signature": "(params?: { page?, pageSize? }) => Promise<ActionState<PaginatedResult<NotificationListItem>>>", "purpose": "获取当前用户通知列表(分页)", "deps": ["requireAuth", "data-access.getNotifications"], "usedBy": ["notification-dropdown.tsx", "notification-list.tsx"] },
{ "name": "markNotificationAsReadAction", "permission": "requireAuth", "signature": "(id: string) => Promise<ActionState<void>>", "purpose": "标记单条通知已读", "deps": ["requireAuth", "data-access.markNotificationAsRead", "revalidatePath"], "usedBy": ["notification-dropdown.tsx", "notification-list.tsx"] },
{ "name": "markAllNotificationsAsReadAction", "permission": "requireAuth", "signature": "() => Promise<ActionState<void>>", "purpose": "标记所有通知已读", "deps": ["requireAuth", "data-access.markAllNotificationsAsRead", "revalidatePath"], "usedBy": ["notification-dropdown.tsx", "notification-list.tsx"] },
{ "name": "getNotificationPreferencesAction", "permission": "requireAuth", "signature": "() => Promise<ActionState<NotificationPreferences>>", "purpose": "获取当前用户的通知偏好设置(首次访问自动创建默认记录)", "deps": ["requireAuth", "notification-preferences.getNotificationPreferences"], "usedBy": ["settings/page.tsx", "settings/components/notification-preferences-form.tsx"] },
{ "name": "updateNotificationPreferencesAction", "permission": "requireAuth", "signature": "(prevState: ActionState<NotificationPreferences> | null, formData: FormData) => Promise<ActionState<NotificationPreferences>>", "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<PaginatedResult<MessageListItem>>", "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<Message | null>", "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<Message[]>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages", "shared.db.schema.users"], "usedBy": ["getMessageDetailAction"] },
{ "name": "createMessage", "signature": "(input: CreateMessageInput) => Promise<Message>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages", "@paralleldrive/cuid2"], "usedBy": ["sendMessageAction"] },
{ "name": "markMessageAsRead", "signature": "(id: string, userId: string) => Promise<void>", "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<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages"], "usedBy": ["deleteMessageAction"] },
{ "name": "getUnreadMessageCount", "signature": "(userId: string) => Promise<number>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messages"], "usedBy": ["待扩展"] },
{ "name": "getNotifications", "signature": "(userId: string, params?: { page?, pageSize? }) => Promise<PaginatedResult<NotificationListItem>>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messageNotifications"], "usedBy": ["getNotificationsAction"] },
{ "name": "createNotification", "signature": "(input: CreateNotificationInput) => Promise<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messageNotifications", "@paralleldrive/cuid2"], "usedBy": ["sendMessageAction (内部调用)"] },
{ "name": "markNotificationAsRead", "signature": "(id: string, userId: string) => Promise<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messageNotifications"], "usedBy": ["markNotificationAsReadAction"] },
{ "name": "markAllNotificationsAsRead", "signature": "(userId: string) => Promise<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messageNotifications"], "usedBy": ["markAllNotificationsAsReadAction"] },
{ "name": "getUnreadNotificationCount", "signature": "(userId: string) => Promise<number>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.messageNotifications"], "usedBy": ["待扩展"] },
{ "name": "getRecipients", "signature": "(ctx: AuthContext) => Promise<RecipientOption[]>", "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<NotificationPreferences>", "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<NotificationPreferences | null>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "purpose": "创建单条考勤记录", "deps": ["requirePermission", "data-access.createAttendanceRecord", "revalidatePath"], "usedBy": ["attendance-record-list.tsx"] },
{ "name": "batchRecordAttendanceAction", "permission": "ATTENDANCE_MANAGE", "signature": "(prevState: ActionState<number> | null, formData: FormData) => Promise<ActionState<number>>", "purpose": "批量点名(班级+日期,表格形式录入每个学生状态)", "deps": ["requirePermission", "data-access.batchCreateAttendanceRecords", "revalidatePath"], "usedBy": ["attendance-sheet.tsx"] },
{ "name": "updateAttendanceAction", "permission": "ATTENDANCE_MANAGE", "signature": "(id: string, prevState: ActionState<string> | null, formData: FormData) => Promise<ActionState<string>>", "purpose": "更新考勤记录(状态、备注)", "deps": ["requirePermission", "data-access.updateAttendanceRecord", "revalidatePath"], "usedBy": ["attendance-record-list.tsx"] },
{ "name": "deleteAttendanceAction", "permission": "ATTENDANCE_MANAGE", "signature": "(id: string) => Promise<ActionState<void>>", "purpose": "删除考勤记录", "deps": ["requirePermission", "data-access.deleteAttendanceRecord", "revalidatePath"], "usedBy": ["attendance-record-list.tsx"] },
{ "name": "getAttendanceAction", "permission": "ATTENDANCE_READ", "signature": "(params?: AttendanceQueryParams) => Promise<ActionState<PaginatedAttendanceResult>>", "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<ActionState<StudentAttendanceSummary>>", "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<ActionState<ClassAttendanceSummary>>", "purpose": "获取班级考勤统计", "deps": ["requirePermission", "data-access-stats.getClassAttendanceStats"], "usedBy": ["teacher/attendance/stats/page.tsx"] },
{ "name": "getClassAttendanceForDateAction", "permission": "ATTENDANCE_READ", "signature": "(classId: string, date: string) => Promise<ActionState<AttendanceListItem[]>>", "purpose": "获取班级指定日期考勤(用于点名页加载已有记录)", "deps": ["requirePermission", "data-access.getClassAttendanceForDate"], "usedBy": ["attendance-sheet.tsx"] },
{ "name": "saveAttendanceRulesAction", "permission": "ATTENDANCE_MANAGE", "signature": "(prevState: ActionState<string> | null, formData: FormData) => Promise<ActionState<string>>", "purpose": "保存班级考勤规则upsert", "deps": ["requirePermission", "data-access.upsertAttendanceRules", "revalidatePath"], "usedBy": ["attendance-rules-form.tsx"] },
{ "name": "getAttendanceRulesAction", "permission": "ATTENDANCE_READ", "signature": "(classId?: string) => Promise<ActionState<AttendanceRule[]>>", "purpose": "获取班级考勤规则", "deps": ["requirePermission", "data-access.getAttendanceRules"], "usedBy": ["attendance-rules-form.tsx"] }
],
"dataAccess": [
{ "name": "getAttendanceRecords", "signature": "(params: AttendanceQueryParams & { scope: DataScope; currentUserId?: string }) => Promise<PaginatedAttendanceResult>", "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<AttendanceListItem[]>", "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<string>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords", "@paralleldrive/cuid2"], "usedBy": ["recordAttendanceAction"] },
{ "name": "batchCreateAttendanceRecords", "signature": "(data: BatchRecordAttendanceInput, recordedBy: string) => Promise<number>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords", "@paralleldrive/cuid2"], "usedBy": ["batchRecordAttendanceAction"] },
{ "name": "updateAttendanceRecord", "signature": "(id: string, data: UpdateAttendanceInput) => Promise<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords"], "usedBy": ["updateAttendanceAction"] },
{ "name": "deleteAttendanceRecord", "signature": "(id: string) => Promise<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRecords"], "usedBy": ["deleteAttendanceAction"] },
{ "name": "getClassStudentsForAttendance", "signature": "(classId: string) => Promise<Array<{ id, name, email }>>", "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<AttendanceRule[]>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.attendanceRules"], "usedBy": ["getAttendanceRulesAction"] },
{ "name": "upsertAttendanceRules", "signature": "(data: AttendanceRuleInput) => Promise<string>", "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<StudentAttendanceSummary | null>", "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<ClassAttendanceSummary | null>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "purpose": "保存班级排课规则upsertclassId 为空时为全局规则)", "deps": ["requirePermission", "data-access.upsertSchedulingRules", "revalidatePath"], "usedBy": ["scheduling-rules-form.tsx"] },
{ "name": "autoScheduleAction", "permission": "SCHEDULE_AUTO", "signature": "(prevState: ActionState<AutoScheduleResult> | null, formData: FormData) => Promise<ActionState<AutoScheduleResult>>", "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<ActionState<number>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "purpose": "提交调课/代课申请status=pending", "deps": ["requirePermission", "data-access.createScheduleChange", "revalidatePath"], "usedBy": ["schedule-change-form.tsx"] },
{ "name": "approveScheduleChangeAction", "permission": "SCHEDULE_AUTO", "signature": "(changeId: string) => Promise<ActionState>", "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<ActionState>", "purpose": "驳回调课申请status=rejected", "deps": ["requirePermission", "data-access.updateScheduleChangeStatus", "revalidatePath"], "usedBy": ["schedule-change-list.tsx"] },
{ "name": "getScheduleChangesAction", "permission": "SCHEDULE_ADJUST", "signature": "(params: ScheduleChangeQueryParams) => Promise<ActionState<ScheduleChangeListItem[]>>", "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<ActionState<ScheduleConflict[]>>", "purpose": "检测班级课表时间重叠冲突", "deps": ["requirePermission", "data-access.getClassConflicts"], "usedBy": ["schedule-conflicts-view.tsx"] }
],
"dataAccess": [
{ "name": "getSchedulingRules", "signature": "(classId?: string) => Promise<SchedulingRule[]>", "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<string>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.schedulingRules", "@paralleldrive/cuid2"], "usedBy": ["saveSchedulingRulesAction"] },
{ "name": "getScheduleChanges", "signature": "(params: ScheduleChangeQueryParams) => Promise<ScheduleChangeListItem[]>", "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<string>", "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<void>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.scheduleChanges"], "usedBy": ["approveScheduleChangeAction", "rejectScheduleChangeAction"] },
{ "name": "getClassConflicts", "signature": "(classId: string) => Promise<ScheduleConflict[]>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.classSchedule"], "usedBy": ["getClassConflictsAction"] },
{ "name": "getAdminClassesForScheduling", "signature": "() => Promise<Array<{ id, name, grade }>>", "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<Array<{ id, name, email }>>", "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<Array<{ id, name, building }>>", "file": "data-access.ts", "deps": ["shared.db", "shared.db.schema.classrooms"], "usedBy": ["autoScheduleAction"] },
{ "name": "getClassSubjectsForScheduling", "signature": "(classId: string) => Promise<Array<{ subjectId, subjectName, teacherId }>>", "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<ActionState<{id:string}>>", "purpose": "学生端上报监考事件(含 submission 归属校验)", "deps": ["requireAuth", "shared/db", "data-access.recordProctoringEvent"], "usedBy": ["anti-cheat-monitor.tsx"]},
{"name": "getProctoringDashboardAction", "permission": "EXAM_PROCTOR", "signature": "(examId: string) => Promise<ActionState<ProctoringDashboardData>>", "purpose": "获取监考面板数据(摘要+学生状态+最近事件)", "deps": ["requirePermission(EXAM_PROCTOR)", "data-access.getExamForProctoring,getExamProctoringSummary,getStudentProctoringStatuses,getRecentProctoringEvents"], "usedBy": ["proctoring-dashboard.tsx"]}
],
"dataAccess": [
{"name": "recordProctoringEvent", "signature": "(input: RecordProctoringEventInput) => Promise<ProctoringEvent>", "purpose": "记录一条监考事件", "usedBy": ["actions.recordProctoringEventAction", "api/proctoring/event/route.ts"]},
{"name": "getProctoringEvents", "signature": "(examId: string, filters?: GetProctoringEventsFilters) => Promise<ProctoringEventWithDetails[]>", "purpose": "查询考试监考事件(含学生姓名、考试标题)", "usedBy": ["待扩展"]},
{"name": "getProctoringEventsBySubmission", "signature": "(submissionId: string) => Promise<ProctoringEvent[]>", "purpose": "查询提交的监考事件", "usedBy": ["待扩展"]},
{"name": "getExamProctoringSummary", "signature": "(examId: string) => Promise<ExamProctoringSummary>", "purpose": "获取考试监考摘要", "usedBy": ["actions.getProctoringDashboardAction", "teacher/exams/[id]/proctoring/page.tsx"]},
{"name": "getStudentProctoringStatuses", "signature": "(examId: string) => Promise<StudentProctoringStatus[]>", "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<ProctoringEventWithDetails[]>", "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<MasteryWithKnowledgePoint[]>", "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<StudentMasterySummary | null>", "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<void>", "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<ClassMasterySummary | null>", "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<KnowledgePointStat[]>", "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<string>", "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<string>", "file": "data-access-reports.ts", "purpose": "生成班级诊断报告聚合班级掌握度识别薄弱知识点status=draftstudentId 存生成者 ID", "deps": ["shared.db", "shared.db.schema.learningDiagnosticReports", "data-access.getClassMasterySummary", "@paralleldrive/cuid2"], "usedBy": ["actions.generateClassReportAction"] },
{ "name": "getDiagnosticReports", "signature": "(filters: DiagnosticReportQueryParams) => Promise<DiagnosticReportWithDetails[]>", "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<DiagnosticReportWithDetails | null>", "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<void>", "file": "data-access-reports.ts", "purpose": "发布诊断报告status=published", "deps": ["shared.db", "shared.db.schema.learningDiagnosticReports"], "usedBy": ["actions.publishReportAction"] },
{ "name": "deleteDiagnosticReport", "signature": "(id: string) => Promise<void>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<ActionState<DiagnosticReportWithDetails[]>>", "file": "actions.ts", "purpose": "查询诊断报告列表(读权限)", "deps": ["requirePermission", "data-access-reports.getDiagnosticReports"], "usedBy": ["待扩展"] },
{ "name": "getDiagnosticReportByIdAction", "permission": "DIAGNOSTIC_READ", "signature": "(id: string) => Promise<ActionState<DiagnosticReportWithDetails | null>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<ActionState<{enrolled:number,waitlist:number}>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<string> | null, formData: FormData) => Promise<ActionState<string>>", "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<ActionState<ElectiveCourseWithDetails[]>>", "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<ActionState<CourseSelectionWithDetails[]>>", "file": "actions.ts", "purpose": "查询学生选课记录(含 DataScope 二次校验class_members 仅自己children 仅子女)", "deps": ["requirePermission(ELECTIVE_READ)", "data-access-selections.getStudentSelections"], "usedBy": ["待扩展"]},
{"name": "getAvailableCoursesAction", "permission": "ELECTIVE_SELECT", "signature": "() => Promise<ActionState<ElectiveCourseWithDetails[]>>", "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<ElectiveCourseWithDetails[]>", "purpose": "查询选修课程列表(按 scope 行级过滤owned/class_taught 按 teacherIdgrade_managed 按 gradeIds", "usedBy": ["actions.getElectiveCoursesAction", "admin/elective/page.tsx", "teacher/elective/page.tsx"]},
{"name": "getElectiveCourseById", "file": "data-access.ts", "signature": "(id: string) => Promise<ElectiveCourseWithDetails | null>", "purpose": "获取课程详情", "usedBy": ["actions.updateElectiveCourseAction", "admin/elective/[id]/edit/page.tsx"]},
{"name": "createElectiveCourse", "file": "data-access.ts", "signature": "(data: CreateElectiveCourseInput, teacherId: string) => Promise<string>", "purpose": "创建选修课程status=draft, enrolledCount=0", "usedBy": ["actions.createElectiveCourseAction"]},
{"name": "updateElectiveCourse", "file": "data-access.ts", "signature": "(id: string, data: Partial<UpdateElectiveCourseInput>) => Promise<void>", "purpose": "更新选修课程字段", "usedBy": ["actions.updateElectiveCourseAction"]},
{"name": "deleteElectiveCourse", "file": "data-access.ts", "signature": "(id: string) => Promise<void>", "purpose": "删除选修课程", "usedBy": ["actions.deleteElectiveCourseAction"]},
{"name": "openSelection", "file": "data-access.ts", "signature": "(courseId: string) => Promise<void>", "purpose": "开放选课status=open", "usedBy": ["actions.openSelectionAction"]},
{"name": "closeSelection", "file": "data-access.ts", "signature": "(courseId: string) => Promise<void>", "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<CourseSelectionWithDetails[]>", "purpose": "查询课程所有选课记录(按 priority, selectedAt 排序)", "usedBy": ["待扩展"]},
{"name": "getStudentSelections", "file": "data-access-selections.ts", "signature": "(studentId: string) => Promise<CourseSelectionWithDetails[]>", "purpose": "查询学生选课记录(按 selectedAt 降序)", "usedBy": ["actions.getStudentSelectionsAction", "student/elective/page.tsx"]},
{"name": "getStudentGradeId", "file": "data-access-selections.ts", "signature": "(studentId: string) => Promise<string | null>", "purpose": "获取学生所在年级 ID通过 classEnrollments active 记录)", "usedBy": ["data-access-selections.getAvailableCoursesForStudent"]},
{"name": "getAvailableCoursesForStudent", "file": "data-access-selections.ts", "signature": "(studentId: string, gradeId?: string | null) => Promise<ElectiveCourseWithDetails[]>", "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/waitlistlottery 模式 selected", "usedBy": ["actions.selectCourseAction"]},
{"name": "dropCourse", "file": "data-access-operations.ts", "signature": "(courseId: string, studentId: string) => Promise<void>", "purpose": "学生退课status=droppedFCFS 模式自动递补 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 默认 30selectionMode 默认 fcfscredit 默认 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/READstudent/parent/grade_head/teaching_head 拥有 GRADE_RECORD_READadmin/teacher 拥有 ATTENDANCE_MANAGE+ATTENDANCE_READstudent/parent/grade_head/teaching_head 拥有 ATTENDANCE_READadmin/teacher/parent/grade_head/teaching_head 拥有 MESSAGE_SEND/READ/DELETEstudent 拥有 MESSAGE_READ/DELETE 但无 MESSAGE_SENDadmin 拥有 SCHEDULE_AUTO+SCHEDULE_ADJUSTteacher 无排课权限admin/teacher 拥有 ELECTIVE_MANAGE+ELECTIVE_READstudent 拥有 ELECTIVE_SELECT+ELECTIVE_READgrade_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_DELETEgrades/actions.ts 使用 GRADE_RECORD_MANAGE/READmessaging/actions.ts 使用 MESSAGE_SEND/READ/DELETEattendance/actions.ts 使用 ATTENDANCE_MANAGE/READscheduling/actions.ts 使用 SCHEDULE_AUTO/SCHEDULE_ADJUSTelective/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_READMessages 菜单项使用 MESSAGE_READAttendance 菜单项 teacher 使用 ATTENDANCE_MANAGEstudent/parent 使用 ATTENDANCE_READScheduling 菜单项 admin 使用 SCHEDULE_ADJUST/SCHEDULE_AUTOteacher Schedule Changes 使用 SCHEDULE_ADJUSTElectives 菜单项 admin/teacher 使用 ELECTIVE_MANAGEstudent 使用 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 必须包含 classIdclass_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 tabNotifications 渲染 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/.xls10MB 上限", "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 <backup_file>"
},
"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"}
}
}
}
}