refactor: RBAC权限系统重构 + UI组件拆分 + 测试修复 + 架构文档
Some checks failed
CI / build-deploy (push) Has been cancelled
Some checks failed
CI / build-deploy (push) Has been cancelled
- RBAC: 新增30个权限点、DataScope行级权限、requirePermission守卫,所有57+ Server Action接入权限校验 - UI拆分: exam-form(1623行→11文件)、textbook-reader(744行→7文件),均降至300行以内 - 测试: 新增5个单元测试文件(19用例),修复4个集成测试文件(38用例全部通过) - 架构文档: 新增架构影响地图(004/005)、标准功能清单(006)、差距审计报告(007) - 项目规则: 架构图优先规则,改码必同步图 - 安全: rehype-sanitize净化、AES加密API Key、权限路由守卫 - 无障碍: skip-link、aria-label、prefers-reduced-motion - 性能: next/font优化、next/image、代码分割
This commit is contained in:
623
docs/architecture/005_architecture_data.json
Normal file
623
docs/architecture/005_architecture_data.json
Normal file
@@ -0,0 +1,623 @@
|
||||
{
|
||||
"_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<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)"]
|
||||
}
|
||||
],
|
||||
"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"]
|
||||
}
|
||||
],
|
||||
"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<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"]},
|
||||
{"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<Session | null>", "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<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": "同上", "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"]}
|
||||
],
|
||||
"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<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错误分析组件"]}
|
||||
],
|
||||
"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<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"]}
|
||||
],
|
||||
"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<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"]}
|
||||
],
|
||||
"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<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? }) => 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": "(classId, scope?) => Promise<ClassStudent[]>", "usedBy": ["teacher/classes/students"]},
|
||||
{"name": "getClassSchedule", "signature": "(classId) => Promise<ClassScheduleItem[]>", "usedBy": ["teacher/classes/schedule"]},
|
||||
{"name": "getClassHomeworkInsights", "signature": "(classId) => Promise<ClassHomeworkInsights | null>", "usedBy": ["classes作业洞察"]},
|
||||
{"name": "getGradeHomeworkInsights", "signature": "(gradeId) => Promise<GradeHomeworkInsights | null>", "usedBy": ["年级作业洞察"]}
|
||||
]
|
||||
}
|
||||
},
|
||||
"school": {
|
||||
"path": "src/modules/school",
|
||||
"description": "学校基础数据管理:学校、年级、部门、学年的CRUD",
|
||||
"exports": {
|
||||
"actions": [
|
||||
{"name": "createSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(prevState, formData) => Promise<ActionState<string>>", "purpose": "创建学校"},
|
||||
{"name": "updateSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(schoolId, prevState, formData) => Promise<ActionState<string>>", "purpose": "更新学校"},
|
||||
{"name": "deleteSchoolAction", "permission": "SCHOOL_MANAGE", "signature": "(schoolId) => Promise<ActionState<string>>", "purpose": "删除学校"},
|
||||
{"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视图"]}
|
||||
]
|
||||
}
|
||||
},
|
||||
"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"]}
|
||||
]
|
||||
}
|
||||
},
|
||||
"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<string, NavItem[]>", "note": "每个NavItem含permission字段用于权限过滤"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"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"]}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"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"}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user