{ "_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" }, "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"], "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"], "student": ["EXAM_READ","HOMEWORK_SUBMIT","QUESTION_READ","TEXTBOOK_READ","CLASS_READ","AI_CHAT"], "parent": ["EXAM_READ","TEXTBOOK_READ","CLASS_READ"], "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"], "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"] }, "dataScopeTypes": { "all": "管理员:无过滤", "owned": "仅自己创建的资源,含 userId 字段", "class_taught": "教师:所教班级,含 classIds[] 和可选 subjectIds[]", "grade_managed": "年级主任:所管年级,含 gradeIds[]", "class_members": "学生:所在班级的成员数据", "children": "家长:子女数据,含 childrenIds[]" }, "modules": { "shared": { "path": "src/shared", "description": "全项目共享基础设施:数据库、工具函数、权限系统、UI组件、Hooks", "exports": { "functions": [ { "name": "cn", "file": "lib/utils.ts", "signature": "cn(...inputs: ClassValue[]): string", "purpose": "合并CSS类名并解决Tailwind冲突", "deps": ["clsx", "tailwind-merge"], "usedBy": ["*所有模块组件"] }, { "name": "formatDate", "file": "lib/utils.ts", "signature": "formatDate(date: string | Date, locale?: string): string", "params": {"date": "日期值", "locale": "Intl locale,默认zh-CN"}, "purpose": "国际化日期格式化", "deps": [], "usedBy": ["exams", "homework", "dashboard", "textbooks"] }, { "name": "parseAiChatPayload", "file": "lib/ai.ts", "signature": "parseAiChatPayload(body: unknown): AiChatRequest", "purpose": "解析并校验AI聊天请求负载", "deps": ["zod"], "usedBy": ["app/api/ai/chat/route.ts"] }, { "name": "encryptAiApiKey", "file": "lib/ai.ts", "signature": "encryptAiApiKey(value: string): string", "purpose": "AES加密AI Provider API Key", "deps": ["crypto"], "usedBy": ["settings/actions.ts"] }, { "name": "decryptAiApiKey", "file": "lib/ai.ts", "signature": "decryptAiApiKey(value: string): string", "purpose": "AES解密AI Provider API Key", "deps": ["crypto"], "usedBy": ["settings/actions.ts", "ai.ts内部"] }, { "name": "testAiProviderConfig", "file": "lib/ai.ts", "signature": "testAiProviderConfig(input: { apiKey: string; baseUrl?: string; model: string }): Promise", "purpose": "测试AI Provider连通性(直接配置)", "deps": ["createAiChatCompletion"], "usedBy": ["settings/actions.ts"] }, { "name": "testAiProviderById", "file": "lib/ai.ts", "signature": "testAiProviderById(providerId: string, overrides?: { baseUrl?: string; model?: string }): Promise", "purpose": "测试AI Provider连通性(按ID)", "deps": ["shared/db", "createAiChatCompletion"], "usedBy": ["settings/actions.ts"] }, { "name": "createAiChatCompletion", "file": "lib/ai.ts", "signature": "createAiChatCompletion(input: AiChatRequest): Promise<{ content: string; usage: unknown }>", "purpose": "调用AI模型生成聊天回复", "deps": ["openai", "shared/db"], "usedBy": ["exams/ai-pipeline.ts", "app/api/ai/chat/route.ts"] }, { "name": "getAiErrorMessage", "file": "lib/ai.ts", "signature": "getAiErrorMessage(v: unknown): string", "purpose": "从AI错误中提取可读消息", "deps": [], "usedBy": ["exams/ai-pipeline.ts"] }, { "name": "getAuthContext", "file": "lib/auth-guard.ts", "signature": "getAuthContext(): Promise", "returns": "AuthContext { userId, roles, permissions, dataScope }", "purpose": "获取当前用户完整认证上下文", "deps": ["auth (NextAuth)", "shared/db"], "usedBy": ["所有业务模块的Server Actions"] }, { "name": "requirePermission", "file": "lib/auth-guard.ts", "signature": "requirePermission(permission: Permission): Promise", "throws": "PermissionDeniedError", "purpose": "断言当前用户拥有指定权限", "deps": ["getAuthContext"], "usedBy": ["所有业务模块的Server Actions"] }, { "name": "checkPermission", "file": "lib/auth-guard.ts", "signature": "checkPermission(permission: Permission): Promise<{ allowed: boolean; ctx: AuthContext }>", "purpose": "非抛出版权限检查", "deps": ["getAuthContext"], "usedBy": [] }, { "name": "requireAuth", "file": "lib/auth-guard.ts", "signature": "requireAuth(): Promise", "purpose": "仅断言用户已登录", "deps": ["getAuthContext"], "usedBy": [] }, { "name": "resolvePermissions", "file": "lib/permissions.ts", "signature": "resolvePermissions(roleNames: string[]): Permission[]", "purpose": "合并多角色的权限列表(去重)", "deps": ["ROLE_PERMISSIONS"], "usedBy": ["auth.ts (JWT callback)"] } ], "hooks": [ { "name": "useActionWithToast", "file": "hooks/use-action-with-toast.ts", "signature": "useActionWithToast(): { isPending: boolean; execute: (action: () => Promise>) => void }", "purpose": "包装Server Action + toast反馈" }, { "name": "useDebounce", "file": "hooks/use-debounce.ts", "signature": "useDebounce(value: T, delay?: number): T", "purpose": "防抖Hook" }, { "name": "useMediaQuery", "file": "hooks/use-media-query.ts", "signature": "useMediaQuery(query: string): boolean", "purpose": "响应式媒体查询Hook" }, { "name": "useLocalStorage", "file": "hooks/use-local-storage.ts", "signature": "useLocalStorage(key: string, initialValue: T): [T, (value: T | ((prev: T) => T)) => void]", "purpose": "localStorage持久化Hook" }, { "name": "usePermission", "file": "hooks/use-permission.ts", "signature": "usePermission(): { permissions: Permission[]; roles: string[]; hasPermission: (p: Permission) => boolean; hasAnyPermission: (...p: Permission[]) => boolean; hasAllPermissions: (...p: Permission[]) => boolean; hasRole: (r: string) => boolean }", "purpose": "客户端权限检查Hook", "usedBy": ["layout/app-sidebar.tsx", "exams/components", "homework/components"] } ], "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/empty-state.tsx", "purpose": "列表空状态展示", "usedBy": ["exams", "homework", "questions", "textbooks"]} ], "types": [ {"name": "ActionState", "file": "types/action-state.ts", "definition": "ActionState = { success: boolean; message?: string; errors?: Record; data?: T }", "usedBy": ["所有模块Server Action"]}, {"name": "Permission", "file": "types/permissions.ts", "definition": "Permission = (typeof Permissions)[keyof typeof Permissions]", "usedBy": ["auth-guard", "use-permission", "所有actions"]}, {"name": "DataScope", "file": "types/permissions.ts", "definition": "DataScope = { type: 'all' } | { type: 'owned'; userId: string } | { type: 'class_taught'; classIds: string[]; subjectIds?: string[] } | { type: 'grade_managed'; gradeIds: string[] } | { type: 'class_members' } | { type: 'children'; childrenIds: string[] }", "usedBy": ["auth-guard", "exams/data-access", "homework/data-access", "dashboard/data-access"]}, {"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","gradeId","departmentId","onboardedAt","createdAt","updatedAt"], "usedBy": ["auth","users","dashboard","classes"]}, "accounts": {"fields": ["userId","type","provider","providerAccountId","refresh_token","access_token"], "usedBy": ["auth"]}, "sessions": {"fields": ["id","sessionToken","userId","expires"], "usedBy": ["auth"]}, "verificationTokens": {"fields": ["identifier","token","expires"], "usedBy": ["auth"]}, "roles": {"fields": ["id","name"], "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","order"], "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","location","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","createdAt","updatedAt"], "usedBy": ["classes","homework","auth-guard"]}, "classSubjectTeachers": {"fields": ["classId","teacherId","subject"], "usedBy": ["classes","auth-guard"]}, "classEnrollments": {"fields": ["classId","studentId","status","joinedAt"], "usedBy": ["classes","homework"]}, "classSchedule": {"fields": ["id","classId","weekday","startTime","endTime","course","location"], "usedBy": ["classes"]}, "exams": {"fields": ["id","creatorId","title","description","subjectId","gradeId","status","difficulty","totalScore","durationMin","scheduledAt","structure","createdAt","updatedAt"], "usedBy": ["exams","homework"]}, "examQuestions": {"fields": ["examId","questionId"], "usedBy": ["exams"]}, "examSubmissions": {"fields": ["id","examId","studentId","score","submittedAt"], "usedBy": ["exams"]}, "submissionAnswers": {"fields": ["id","submissionId","questionId","answer","score","feedback"], "usedBy": ["exams"]}, "homeworkAssignments": {"fields": ["id","creatorId","sourceExamId","title","description","status","availableAt","dueAt","allowLate","lateDueAt","maxAttempts","createdAt","updatedAt"], "usedBy": ["homework"]}, "homeworkAssignmentQuestions": {"fields": ["assignmentId","questionId"], "usedBy": ["homework"]}, "homeworkAssignmentTargets": {"fields": ["assignmentId","studentId"], "usedBy": ["homework"]}, "homeworkSubmissions": {"fields": ["id","assignmentId","studentId","status","attemptNo","score","submittedAt"], "usedBy": ["homework"]}, "homeworkAnswers": {"fields": ["id","submissionId","questionId","answer","score","feedback"], "usedBy": ["homework"]}, "aiProviders": {"fields": ["id","provider","baseUrl","model","apiKeyEncrypted","isDefault","updatedAt"], "usedBy": ["settings","ai"]} } }, "auth": { "path": "src/auth.ts", "description": "用户认证:NextAuth配置、JWT/Session callbacks、middleware", "exports": { "functions": [ {"name": "auth", "signature": "auth(): Promise", "purpose": "获取当前用户Session", "usedBy": ["auth-guard.ts", "所有Server Component页面"]}, {"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"]} ] }, "middleware": { "file": "src/proxy.ts", "signature": "middleware(request: NextRequest): Promise", "purpose": "基于权限点的路由守卫", "routePermissions": { "/admin": "school:manage", "/teacher": "exam:read", "/student": "homework:submit", "/parent": "exam:read", "/management": "grade:manage" }, "apiPermissions": { "/api/ai/chat": "ai:chat" } } }, "exams": { "path": "src/modules/exams", "description": "考试全生命周期:创建(手动/AI)、编辑、预览、发布、删除、复制", "exports": { "actions": [ {"name": "createExamAction", "permission": "EXAM_CREATE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "手动模式创建考试草稿", "deps": ["requirePermission","shared/db","data-access.persistExamDraft"], "usedBy": ["exam-form.tsx"]}, {"name": "createAiExamAction", "permission": "EXAM_AI_GENERATE", "signature": "同上", "purpose": "AI模式创建考试", "deps": ["requirePermission","ai-pipeline.generateAiCreateDraftFromSource","data-access.persistAiGeneratedExamDraft"], "usedBy": ["exam-form.tsx"]}, {"name": "previewAiExamAction", "permission": "EXAM_AI_GENERATE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "AI预览试卷(不持久化)", "deps": ["requirePermission","ai-pipeline.generateAiPreviewData"], "usedBy": ["exam-ai-generator.tsx"]}, {"name": "regenerateAiQuestionAction", "permission": "EXAM_AI_GENERATE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "AI重写单个题目", "deps": ["requirePermission","ai-pipeline.regenerateAiQuestionByInstruction"], "usedBy": ["exam-preview-question-editor.tsx"]}, {"name": "updateExamAction", "permission": "EXAM_UPDATE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "更新考试(含资源归属校验)", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-form.tsx"]}, {"name": "deleteExamAction", "permission": "EXAM_DELETE", "signature": "同上", "purpose": "删除考试(含资源归属校验)", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-actions.tsx"]}, {"name": "duplicateExamAction", "permission": "EXAM_DUPLICATE", "signature": "同上", "purpose": "复制考试", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-actions.tsx"]}, {"name": "getExamPreviewAction", "permission": "EXAM_READ", "signature": "同上", "purpose": "获取考试预览数据", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-viewer.tsx"]}, {"name": "getSubjectsAction", "permission": "EXAM_READ", "signature": "() => Promise>", "purpose": "获取科目列表", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-form.tsx"]}, {"name": "getGradesAction", "permission": "EXAM_READ", "signature": "同上", "purpose": "获取年级列表", "deps": ["requirePermission","shared/db"], "usedBy": ["exam-form.tsx"]} ], "dataAccess": [ {"name": "getExams", "signature": "getExams(params: GetExamsParams & { scope: DataScope }): Promise", "purpose": "查询考试列表(含数据权限过滤)", "usedBy": ["teacher/exams/all/page.tsx", "homework创建页面"]}, {"name": "getExamById", "signature": "getExamById(id: string, scope?: DataScope): Promise", "purpose": "按ID获取考试详情", "usedBy": ["exam详情/编辑页面"]}, {"name": "persistExamDraft", "signature": "persistExamDraft(input: { examId, title, creatorId, subjectId, gradeId, scheduledAt?, description }): Promise", "purpose": "持久化手动考试草稿", "usedBy": ["createExamAction"]}, {"name": "persistAiGeneratedExamDraft", "signature": "persistAiGeneratedExamDraft(input: { examId, title, creatorId, subjectId, gradeId, scheduledAt?, description, structure, generated }): Promise", "purpose": "持久化AI生成考试草稿", "usedBy": ["createAiExamAction"]} ], "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"]} ], "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"]} ] } }, "homework": { "path": "src/modules/homework", "description": "作业全生命周期:创建(源自考试)、发布、学生作答、教师批改、数据分析", "exports": { "actions": [ {"name": "createHomeworkAssignmentAction", "permission": "HOMEWORK_CREATE", "signature": "(prevState: ActionState | null, formData: FormData) => Promise>", "purpose": "从已有考试创建作业", "deps": ["requirePermission","shared/db","exams/data-access.getExams"], "usedBy": ["homework-assignment-form.tsx"]}, {"name": "startHomeworkSubmissionAction", "permission": "HOMEWORK_SUBMIT", "signature": "同上", "purpose": "学生开始作答", "deps": ["requirePermission","shared/db"], "usedBy": ["homework-take-view.tsx"]}, {"name": "saveHomeworkAnswerAction", "permission": "HOMEWORK_SUBMIT", "signature": "同上", "purpose": "保存单题答案", "deps": ["requirePermission","shared/db"], "usedBy": ["homework-take-view.tsx"]}, {"name": "submitHomeworkAction", "permission": "HOMEWORK_SUBMIT", "signature": "同上", "purpose": "提交作业", "deps": ["requirePermission","shared/db"], "usedBy": ["homework-take-view.tsx"]}, {"name": "gradeHomeworkSubmissionAction", "permission": "HOMEWORK_GRADE", "signature": "同上", "purpose": "教师批改作业", "deps": ["requirePermission","shared/db"], "usedBy": ["homework-grading-view.tsx"]} ], "dataAccess": [ {"name": "getTeacherGradeTrends", "signature": "(teacherId: string, limit?: number) => Promise", "usedBy": ["dashboard (教师仪表盘)"]}, {"name": "getHomeworkAssignments", "signature": "(params?: { creatorId?, ids?, classId?, scope? }) => Promise", "usedBy": ["teacher作业列表页", "homework-assignment-form.tsx"]}, {"name": "getHomeworkAssignmentReviewList", "signature": "(params: { creatorId: string; scope? }) => Promise", "usedBy": ["teacher批改列表"]}, {"name": "getHomeworkSubmissions", "signature": "(params?: { assignmentId?, classId?, creatorId?, scope? }) => Promise", "usedBy": ["teacher提交列表"]}, {"name": "getStudentHomeworkAssignments", "signature": "(studentId: string) => Promise", "usedBy": ["student/dashboard"]}, {"name": "getStudentDashboardGrades", "signature": "(studentId: string) => Promise", "usedBy": ["dashboard/data-access.ts"]}, {"name": "getHomeworkAssignmentAnalytics", "signature": "(assignmentId: string) => Promise", "usedBy": ["homework错误分析组件"]} ], "types": [ {"name": "StudentDashboardGradeProps", "definition": "{ trend, recent, ranking }", "usedBy": ["dashboard/types.ts"]}, {"name": "HomeworkAssignmentListItem", "usedBy": ["homework列表页"]}, {"name": "StudentHomeworkTakeData", "usedBy": ["homework-take-view.tsx"]} ] } }, "questions": { "path": "src/modules/questions", "description": "题库管理:题目CRUD、知识点关联、多题型支持", "exports": { "actions": [ {"name": "createNestedQuestion", "permission": "QUESTION_CREATE", "signature": "(prevState: ActionState | undefined, formData: FormData | CreateQuestionInput) => Promise>", "purpose": "创建题目(含嵌套)", "deps": ["requirePermission","shared/db"], "usedBy": ["create-question-dialog.tsx"]}, {"name": "updateQuestionAction", "permission": "QUESTION_UPDATE", "signature": "同上", "purpose": "更新题目", "deps": ["requirePermission","shared/db"], "usedBy": ["question-actions.tsx"]}, {"name": "deleteQuestionAction", "permission": "QUESTION_DELETE", "signature": "同上", "purpose": "删除题目", "deps": ["requirePermission","shared/db"], "usedBy": ["question-actions.tsx"]}, {"name": "getQuestionsAction", "permission": "QUESTION_READ", "signature": "(params: GetQuestionsParams) => Promise<...>", "purpose": "查询题目列表", "deps": ["requirePermission","data-access.getQuestions"], "usedBy": ["teacher/questions/page.tsx"]}, {"name": "getKnowledgePointOptionsAction", "permission": "QUESTION_READ", "signature": "() => Promise", "purpose": "获取知识点选项", "deps": ["requirePermission","shared/db"], "usedBy": ["create-question-dialog.tsx"]} ], "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"]} ] } }, "textbooks": { "path": "src/modules/textbooks", "description": "教材与知识体系:教材/章节树形结构、知识点CRUD、Markdown内容编辑、知识图谱", "exports": { "actions": [ {"name": "createTextbookAction", "permission": "TEXTBOOK_CREATE", "signature": "(prevState, formData) => Promise", "purpose": "创建教材"}, {"name": "updateTextbookAction", "permission": "TEXTBOOK_UPDATE", "signature": "(textbookId, prevState, formData) => Promise", "purpose": "更新教材元信息"}, {"name": "deleteTextbookAction", "permission": "TEXTBOOK_DELETE", "signature": "(textbookId) => Promise", "purpose": "删除教材"}, {"name": "createChapterAction", "permission": "TEXTBOOK_CREATE", "signature": "(textbookId, parentId?, prevState, formData) => Promise", "purpose": "创建章节"}, {"name": "updateChapterContentAction", "permission": "TEXTBOOK_UPDATE", "signature": "(chapterId, content, textbookId) => Promise", "purpose": "更新章节内容(Markdown)"}, {"name": "deleteChapterAction", "permission": "TEXTBOOK_DELETE", "signature": "(chapterId, textbookId) => Promise", "purpose": "删除章节"}, {"name": "createKnowledgePointAction", "permission": "TEXTBOOK_CREATE", "signature": "(chapterId, textbookId, prevState, formData) => Promise", "purpose": "创建知识点"}, {"name": "updateKnowledgePointAction", "permission": "TEXTBOOK_UPDATE", "signature": "(kpId, textbookId, prevState, formData) => Promise", "purpose": "更新知识点"}, {"name": "deleteKnowledgePointAction", "permission": "TEXTBOOK_DELETE", "signature": "(kpId, textbookId) => Promise", "purpose": "删除知识点"}, {"name": "reorderChaptersAction", "permission": "TEXTBOOK_UPDATE", "signature": "(chapterId, newIndex, parentId, textbookId) => Promise", "purpose": "章节排序"} ], "dataAccess": [ {"name": "getTextbooks", "signature": "(query?, subject?, grade?) => Promise", "usedBy": ["teacher/textbooks/page.tsx"]}, {"name": "getTextbookById", "signature": "(id) => Promise", "usedBy": ["teacher/textbooks/[id]/page.tsx"]}, {"name": "getChaptersByTextbookId", "signature": "(textbookId) => Promise", "usedBy": ["textbook-reader.tsx"]}, {"name": "getKnowledgePointsByChapterId", "signature": "(chapterId) => Promise", "usedBy": ["textbook-reader.tsx"]}, {"name": "getKnowledgePointsByTextbookId", "signature": "(textbookId) => Promise", "usedBy": ["textbook-reader.tsx"]} ], "hooks": [ {"name": "useTextSelection", "file": "hooks/use-text-selection.ts", "signature": "(contentRef, onCreateKP) => { selectedText, createDialogOpen, isCreating, handleContentPointerDown, handleContextMenuChange }", "usedBy": ["textbook-content-panel.tsx"]}, {"name": "useKnowledgePointActions", "file": "hooks/use-knowledge-point-actions.ts", "signature": "(textbookId, selectedChapterId, highlightedKpId, setHighlightedKpId) => { editingKp, editKpDialogOpen, ..., requestDeleteKP, confirmDeleteKP, handleUpdateKP }", "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"]} ] } }, "classes": { "path": "src/modules/classes", "description": "班级管理:班级CRUD、学生注册/退班、邀请码、课表、学科教师分配", "exports": { "actions": [ {"name": "createTeacherClassAction", "permission": "CLASS_CREATE", "signature": "(prevState, formData) => Promise>", "purpose": "教师创建班级"}, {"name": "updateTeacherClassAction", "permission": "CLASS_UPDATE", "signature": "(classId, prevState, formData) => Promise", "purpose": "教师更新班级"}, {"name": "deleteTeacherClassAction", "permission": "CLASS_DELETE", "signature": "(classId) => Promise", "purpose": "教师删除班级"}, {"name": "createGradeClassAction", "permission": "CLASS_CREATE", "signature": "(prevState, formData) => Promise>", "purpose": "年级主任创建班级"}, {"name": "updateGradeClassAction", "permission": "CLASS_UPDATE", "signature": "(classId, prevState, formData) => Promise", "purpose": "年级主任更新班级"}, {"name": "deleteGradeClassAction", "permission": "CLASS_DELETE", "signature": "(classId) => Promise", "purpose": "年级主任删除班级"}, {"name": "enrollStudentByEmailAction", "permission": "CLASS_ENROLL", "signature": "(classId, prevState, formData) => Promise", "purpose": "通过邮箱注册学生"}, {"name": "joinClassByInvitationCodeAction", "permission": "CLASS_ENROLL", "signature": "(prevState, formData) => Promise>", "purpose": "通过邀请码加入"}, {"name": "ensureClassInvitationCodeAction", "permission": "CLASS_ENROLL", "signature": "(classId) => Promise>", "purpose": "确保邀请码存在"}, {"name": "regenerateClassInvitationCodeAction", "permission": "CLASS_ENROLL", "signature": "(classId) => Promise>", "purpose": "重新生成邀请码"}, {"name": "setStudentEnrollmentStatusAction", "permission": "CLASS_ENROLL", "signature": "(classId, studentId, status) => Promise", "purpose": "设置学生状态"}, {"name": "createClassScheduleItemAction", "permission": "CLASS_SCHEDULE", "signature": "(prevState, formData) => Promise>", "purpose": "创建课表项"}, {"name": "updateClassScheduleItemAction", "permission": "CLASS_SCHEDULE", "signature": "(scheduleId, prevState, formData) => Promise", "purpose": "更新课表项"}, {"name": "deleteClassScheduleItemAction", "permission": "CLASS_SCHEDULE", "signature": "(scheduleId) => Promise", "purpose": "删除课表项"}, {"name": "createAdminClassAction", "permission": "CLASS_CREATE", "signature": "(prevState, formData) => Promise>", "purpose": "管理员创建班级"}, {"name": "updateAdminClassAction", "permission": "CLASS_UPDATE", "signature": "(classId, prevState, formData) => Promise", "purpose": "管理员更新班级"}, {"name": "deleteAdminClassAction", "permission": "CLASS_DELETE", "signature": "(classId) => Promise", "purpose": "管理员删除班级"} ], "dataAccess": [ {"name": "getTeacherClasses", "signature": "(params?: { teacherId? }) => Promise", "usedBy": ["teacher/classes/my", "dashboard"]}, {"name": "getAdminClasses", "signature": "() => Promise", "usedBy": ["admin班级管理"]}, {"name": "getGradeManagedClasses", "signature": "(userId) => Promise", "usedBy": ["grade_head班级管理"]}, {"name": "getStudentClasses", "signature": "(studentId) => Promise", "usedBy": ["student/dashboard"]}, {"name": "getStudentSchedule", "signature": "(studentId) => Promise", "usedBy": ["student课表"]}, {"name": "getClassStudents", "signature": "(classId, scope?) => Promise", "usedBy": ["teacher/classes/students"]}, {"name": "getClassSchedule", "signature": "(classId) => Promise", "usedBy": ["teacher/classes/schedule"]}, {"name": "getClassHomeworkInsights", "signature": "(classId) => Promise", "usedBy": ["classes作业洞察"]}, {"name": "getGradeHomeworkInsights", "signature": "(gradeId) => Promise", "usedBy": ["年级作业洞察"]} ] } }, "school": { "path": "src/modules/school", "description": "学校基础数据管理:学校、年级、部门、学年的CRUD", "exports": { "actions": [ {"name": "createSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(prevState, formData) => Promise>", "purpose": "创建学校"}, {"name": "updateSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(schoolId, prevState, formData) => Promise>", "purpose": "更新学校"}, {"name": "deleteSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(schoolId) => Promise>", "purpose": "删除学校"}, {"name": "createGradeAction", "permission": "GRADE_MANAGE", "signature": "(prevState, formData) => Promise>", "purpose": "创建年级"}, {"name": "updateGradeAction", "permission": "GRADE_MANAGE", "signature": "(gradeId, prevState, formData) => Promise>", "purpose": "更新年级"}, {"name": "deleteGradeAction", "permission": "GRADE_MANAGE", "signature": "(gradeId) => Promise>", "purpose": "删除年级"}, {"name": "createDepartmentAction", "permission": "SCHOOL_MANAGE", "signature": "(prevState, formData) => Promise>", "purpose": "创建部门"}, {"name": "updateDepartmentAction", "permission": "SCHOOL_MANAGE", "signature": "(departmentId, prevState, formData) => Promise>", "purpose": "更新部门"}, {"name": "deleteDepartmentAction", "permission": "SCHOOL_MANAGE", "signature": "(departmentId) => Promise>", "purpose": "删除部门"}, {"name": "createAcademicYearAction", "permission": "SCHOOL_MANAGE", "signature": "(prevState, formData) => Promise>", "purpose": "创建学年"}, {"name": "updateAcademicYearAction", "permission": "SCHOOL_MANAGE", "signature": "(academicYearId, prevState, formData) => Promise>", "purpose": "更新学年"}, {"name": "deleteAcademicYearAction", "permission": "SCHOOL_MANAGE", "signature": "(academicYearId) => Promise>", "purpose": "删除学年"} ], "dataAccess": [ {"name": "getSchools", "signature": "() => Promise", "usedBy": ["admin学校管理", "onboarding"]}, {"name": "getGrades", "signature": "() => Promise", "usedBy": ["admin年级管理", "exams", "onboarding"]}, {"name": "getDepartments", "signature": "() => Promise", "usedBy": ["admin部门管理"]}, {"name": "getAcademicYears", "signature": "() => Promise", "usedBy": ["admin学年管理"]}, {"name": "getStaffOptions", "signature": "() => Promise", "usedBy": ["school组件"]}, {"name": "getGradesForStaff", "signature": "(staffId) => Promise", "usedBy": ["grade_head视图"]} ] } }, "dashboard": { "path": "src/modules/dashboard", "description": "各角色仪表盘数据聚合与展示", "exports": { "dataAccess": [ {"name": "getAdminDashboardData", "signature": "(scope?: DataScope) => Promise", "deps": ["shared/db", "DataScope"], "usedBy": ["admin/dashboard/page.tsx"]} ], "types": [ {"name": "StudentDashboardProps", "definition": "{ studentName, enrolledClassCount, dueSoonCount, overdueCount, gradedCount, todayScheduleItems, upcomingAssignments, grades }", "deps": ["homework/types.StudentDashboardGradeProps"], "usedBy": ["student-dashboard-view.tsx"]}, {"name": "TeacherDashboardData", "definition": "{ classes, schedule, assignments, submissions, teacherName, gradeTrends }", "deps": ["homework/data-access.getTeacherGradeTrends", "classes/data-access.getTeacherClasses"], "usedBy": ["teacher-dashboard-view.tsx"]}, {"name": "AdminDashboardData", "definition": "{ activeSessionsCount, userCount, userRoleCounts, classCount, ... }", "usedBy": ["admin/dashboard/page.tsx"]} ] } }, "layout": { "path": "src/modules/layout", "description": "应用布局框架:侧边栏、顶栏、导航配置", "exports": { "components": [ {"name": "AppSidebar", "purpose": "根据权限渲染侧边栏导航", "internalDeps": ["usePermission", "NAV_CONFIG"]}, {"name": "SiteHeader", "purpose": "顶部导航栏", "internalDeps": ["useSession", "signOut"]} ], "config": [ {"name": "NAV_CONFIG", "type": "Record", "note": "每个NavItem含permission字段用于权限过滤"} ] } }, "settings": { "path": "src/modules/settings", "description": "系统设置:AI Provider配置、用户偏好", "exports": { "actions": [ {"name": "getAiProviderSummaries", "permission": "AI_CONFIGURE", "signature": "() => Promise", "purpose": "获取AI Provider列表"}, {"name": "upsertAiProviderAction", "permission": "AI_CONFIGURE", "signature": "(data) => Promise>", "purpose": "创建/更新AI Provider", "deps": ["shared/lib/ai (encrypt/decrypt)"]}, {"name": "testAiProviderAction", "permission": "AI_CONFIGURE", "signature": "(data) => Promise>", "purpose": "测试AI Provider连通性", "deps": ["shared/lib/ai.testAiProviderConfig"]} ] } } }, "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"], "uses": {"shared": ["hooks.usePermission"], "auth": ["useSession"]}}, "settings": {"dependsOn": ["shared", "auth"], "uses": {"shared": ["db", "auth-guard", "ai", "types"], "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)" ] }, "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" ] }, "permission": { "origin": "shared/types/permissions.ts Permissions 常量定义", "flow": [ "shared/lib/permissions.ts ROLE_PERMISSIONS → 角色到权限映射", "auth.ts JWT callback → resolvePermissions(roleNames) → token.permissions", "proxy.ts middleware → token.permissions → 路由权限检查", "auth-guard.ts requirePermission(permission) → Server Action权限断言", "use-permission.ts hasPermission(permission) → 客户端条件渲染", "layout/config/navigation.ts NavItem.permission → 侧边栏菜单过滤" ] }, "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' 时校验资源归属" ] } }, "routes": { "auth": { "/login": {"component": "LoginForm", "type": "client", "module": "auth"}, "/register": {"component": "RegisterForm + registerAction", "type": "server", "module": "auth"} }, "admin": { "/admin/dashboard": {"component": "AdminDashboardView", "type": "server", "dataAccess": ["dashboard/data-access.getAdminDashboardData"], "permission": "school: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"} }, "student": { "/student/dashboard": {"component": "StudentDashboardView", "type": "server", "dataAccess": ["dashboard/data-access (student)", "homework/data-access.getStudentDashboardGrades", "classes/data-access.getStudentClasses"], "permission": "homework:submit"} }, "parent": { "/parent/dashboard": {"component": "ParentDashboardView", "type": "client", "permission": "exam:read"} }, "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"} } }, "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"} } }