Files
NextEdu/docs/feature/f_bk_design.md
SpecialX 978d9a8309
Some checks failed
Security / deep-security-scan (push) Failing after 20m5s
DR Drill / dr-drill (push) Failing after 1m31s
CI / scheduled-backup (push) Failing after 1m31s
CI / backup-verify (push) Has been skipped
CI / weekly-dr-drill (push) Failing after 0s
CI / build-deploy (push) Has been cancelled
CI / security-scan (push) Has been cancelled
feat: 新增备课模块并修复全模块 P0/P1/P2 缺陷
主要变更:

- 新增 lesson-preparation 模块: 备课编辑器、节点编辑、AI 建议、知识点选择、版本历史、作业发布

- 新增 shared 通用组件: charts/question-bank-filters/schedule-list/ui (chip-nav/filter-bar/page-header/stat-card/stat-item)

- 新增 student/admin 端 loading.tsx 与 error.tsx, 优化加载与错误态体验

- 新增 teacher/lesson-plans 页面 (列表/新建/编辑)

- 新增 drizzle 迁移 0002_tiny_lionheart 及 snapshot

- 新增 textbooks/schema.ts 与 exams/utils/normalize-structure.ts

- 修复 Tiptap v3 SSR hydration 崩溃 (rich-text-block immediatelyRender: false)

- 重构多模块 data-access/actions/组件, 修复权限校验与类型规范

- 同步架构文档 004/005 反映新增模块、导出、依赖关系

- 归档 bugs/* 测试报告与 e2e 测试脚本 (admin/parent/student/teacher web_test)
2026-06-22 01:06:16 +08:00

27 KiB
Raw Permalink Blame History

备课模块lesson-preparation设计文档

配套原型:docs/feature/f_bk.md 架构依据:docs/architecture/004_architecture_impact_map.md005_architecture_data.json 编写日期2026-06-18 范围:P0 地基 + P1 联动P2 协作 / P3 AI 与学情回看留作后续 spec


0. 关键决策摘要

决策项 最终选择 理由
本次 spec 范围 P0 + P1 构成"备课→出题→下发"最小可用闭环,体量适中
编辑器形态 Block 编辑器为主 与蓝图文字一致;设计稿的"课文+节点画布"作为 text_study block 的内部交互
Block 存储模型 方案 AJSON 文档 + 版本快照表 与现有 questions.content / homeworkAssignments.structure 的 JSON 模式一致;为 P2 批注 / P3 AI 重写预留稳定 blockId 锚点;零跨模块 DB 访问
知识点同步 P1 仅"关联已有 + AI 推荐",不回写教材树 避免 P1 引入审核流拖慢闭环;回写留作后续 spec
作业发布闭环 复用 exam 中转 课案练习块 → 打包成 exam 草稿 → 调用现有 createHomeworkAssignmentAction 下发;零 schema 侵入、溯源清晰作业→exam→课案

1. 模块定位与边界

1.1 模块名

lesson-preparation(目录 src/modules/lesson-preparation/),中文"备课"。

1.2 与 course-plans 的关系(互补,不合并)

模块 粒度 回答的问题
course-plans 学期/周宏观排课totalHours/weeklyHours/week/topic "这学期每周教什么"
lesson-preparation 具体一节课的教学设计(目标/重难点/导入/新授/练习/作业…) "这节课怎么教"

软关联:课案可记录来源 coursePlanItemId(可空,无强外键),便于"周计划→具体课案"下钻。

1.3 依赖关系(严格三层架构,零跨模块直查)

  • 依赖 shared/*@/auth
  • 通过对方 data-access 通信(不直接查询对方表):
    • textbooks — 只读章节树 / 知识点树
    • questions — 创建题目(含知识点关联)、查询题目
    • exams — 创建 exam 草稿(用于发布中转)
    • homework — 创建作业下发到班级
    • classes — 查询教师班级(用于下发目标选择)
    • files — 附件引用
  • 被依赖P0/P1 阶段无被依赖方

2. 数据模型(新增 3 张表)

2.1 lesson_plans(课案主表)

字段 类型 约束 说明
id id PK CUID2
title varchar(255) notNull 课案标题
textbookId varchar(128) FK→textbooks, nullable 教材(允许非教材备课)
chapterId varchar(128) FK→chapters, nullable 章节
coursePlanItemId varchar(128) nullable, 无 FK 软关联课程计划项
subjectId varchar(128) FK→subjects, nullable 学科
gradeId varchar(128) FK→grades, nullable 年级
templateId varchar(128) nullable 使用的模板 ID
templateName varchar(100) nullable 模板名快照(防模板改名)
content json notNull block 文档 JSON见 §3
status varchar(50) default 'draft' draft/published/archived
creatorId varchar(128) FK→users, notNull 创建者
lastSavedAt timestamp nullable 最后自动保存时间
createdAt timestamp defaultNow
updatedAt timestamp defaultNow onUpdateNow

索引:creatorIdx(creatorId)statusIdx(status)textbookChapterIdx(textbookId, chapterId)subjectGradeIdx(subjectId, gradeId)

2.2 lesson_plan_versions(版本快照表)

字段 类型 约束 说明
id id PK
planId varchar(128) FK→lesson_plans, onDelete cascade
versionNo int notNull 每 plan 内自增
label varchar(100) nullable 手动保存时的标签
content json notNull 该版本 content 快照
isAuto boolean default false true=自动保存触发
creatorId varchar(128) FK→users, notNull
createdAt timestamp defaultNow

索引:planVersionIdx(planId, versionNo)(唯一)、planCreatedIdx(planId, createdAt desc)

2.3 lesson_plan_templates(模板表)

字段 类型 约束 说明
id id PK
name varchar(100) notNull 模板名
type varchar(50) notNull system/personal
scope varchar(50) notNull regular/review/experiment/inquiry/blank/custom
blocks json notNull 预置 block 骨架blockType + 默认标题 + 提示语,无内容)
creatorId varchar(128) FK→users, nullable personal 模板拥有者system 为 null
createdAt timestamp defaultNow
updatedAt timestamp defaultNow onUpdateNow

索引:typeCreatorIdx(type, creatorId)personal 模板按创建者过滤)

系统预设 4+1 套模板由 seed 脚本写入type=system。教师"另存为我的模板"写入 type=personal。


3. Block 文档 JSON 结构

3.1 顶层结构

{
  "version": 1,
  "blocks": [
    {
      "id": "blk_xxx",
      "type": "objective",
      "title": "教学目标",
      "data": { },
      "order": 0
    }
  ]
}
  • id:客户端生成的稳定 IDCUID2是 P2 批注锚点、P3 AI 单 block 重写的定位依据
  • type:见 §3.2 枚举
  • title:环节名(可改,模板提供默认值)
  • data:类型相关数据,见 §3.3
  • order:排序索引(整数,编辑器拖拽后重排)

3.2 Block 类型枚举

type 用途 出现模板
objective 教学目标 常规/复习/实验
key_point 教学重难点 常规
import 导入 常规
new_teaching 新授 常规
consolidation 巩固 常规
summary 小结 常规/复习/实验/探究
homework 作业布置(文字描述型) 常规
blackboard 板书设计 常规
text_study 文本研习(设计稿画布形态) 语文/英语精读课自定义添加
exercise 练习/作业块P1 核心,关联题目) 任意模板可添加
rich_text 通用富文本(自定义环节) 复习/实验/探究的自定义环节
reflection 教学反思P3 预留P0/P1 不渲染特殊 UI 任意

3.3 各 block.data 结构

富文本类objective/key_point/import/new_teaching/consolidation/summary/homework/blackboard/rich_text/reflection

{
  "html": "<p>...</p>",
  "knowledgePointIds": ["kp_1", "kp_2"]
}

text_study(设计稿画布形态的 block 化):

{
  "sourceText": "天气凉了,树叶黄了...",
  "annotations": [
    {
      "id": "ann_xxx",
      "anchor": { "start": 12, "end": 20 },
      "nodeType": "language_feature",
      "title": "语言特色",
      "note": "关注'那么'的反复",
      "color": "yellow"
    }
  ],
  "knowledgePointIds": ["kp_1"]
}

exerciseP1 核心):

{
  "items": [
    {
      "questionId": "q_xxx",
      "source": "bank",
      "score": 5,
      "order": 0
    },
    {
      "questionId": "inline_draft_xxx",
      "source": "inline",
      "inlineContent": {
        "content": { },
        "type": "single_choice",
        "difficulty": 3,
        "knowledgePointIds": ["kp_1"]
      },
      "score": 10,
      "order": 1
    }
  ],
  "purpose": "class_practice",
  "knowledgePointIds": ["kp_1"]
}
  • sourcebank=从题库拉取questionId 已存在于 questions 表);inline=课案内新建(编辑期 questionId 为占位 inline_draft_${cuid},发布时入库后回填真实 ID
  • inlineContent:仅 source=inline 时存在,结构与 questions 表字段对齐content/type/difficulty/knowledgePointIds发布时作为 createQuestionWithRelations 的入参
  • purposeclass_practice=课堂练习;after_class_homework=课后作业(发布闭环仅处理此类型)

4. 模板系统

4.1 系统预设模板4+1 套,由 seed 脚本写入)

模板 scope block 序列
常规课 regular objective → key_point → import → new_teaching → consolidation → summary → homework → blackboard
复习课 review objective → rich_text("知识网络梳理") → rich_text("典型例题精讲") → rich_text("变式训练") → exercise("当堂检测") → summary
实验课 experiment objective → rich_text("器材准备") → rich_text("实验步骤") → rich_text("观察记录表") → rich_text("交流讨论") → summary
探究课 inquiry rich_text("情境导入") → rich_text("问题驱动") → rich_text("小组探究") → rich_text("成果展示") → rich_text("归纳提升")
空白 blank (无预置 block

模板 blocks JSON 仅定义骨架type + 默认 title + 提示语),不含内容。教师选用后生成对应 block 序列,可自由增删、改序、改名、改内容。

4.2 自定义模板

  • 教师在编辑器内"另存为我的模板"→ 写入 lesson_plan_templatestype=personal, creatorId=教师)
  • personal 模板仅创建者可见、可编辑、可删除
  • 创建课案时模板选择器并列展示 system + 我的 personal 模板

5. Block 编辑器与版本管理

5.1 编辑器交互

  • 主体:可拖拽 block 列表(类 Notion/BlockNote 的块状编辑器)
  • 每个 block标题栏可改名+ 内容区(按 type 渲染不同编辑组件)+ 拖拽手柄 + 删除/上移/下移/复制
  • block 增删:顶部"+"按钮选择 block 类型插入;可从模板侧栏拖入预置环节
  • 自动保存:编辑器 debounce 3s 无操作后触发自动保存(写 lesson_plans.content + lastSavedAt,不生成版本)
  • 手动保存Ctrl+S 或按钮 → 生成新版本(写 lesson_plan_versionsisAuto=false
  • 版本历史侧栏抽屉展示版本列表versionNo + label + 时间 + isAuto 标记),点击预览该版本 content"回退到此版本"= 用该版本 content 覆盖当前 + 生成新版本

5.2 版本策略

  • 自动保存:只更新 lesson_plans.contentlastSavedAt写 versions 表(避免版本爆炸)
  • 手动保存:写一条 versions 记录isAuto=false
  • 定时自动版本:每 30 分钟若有过改动,自动写一条 versions 记录isAuto=true防止教师长时间未手动保存丢失历史
  • 版本上限:每 plan 保留最近 50 条 versions超出删除最旧的 isAuto=true 记录(手动版本永不被自动清理)

5.3 我的课案库

  • 路由:/teacher/lesson-plans
  • 列表展示:卡片网格,显示 title / 教材章节 / 学科年级 / 模板 / status / 最后保存时间
  • 筛选:教材(级联章节)、学科、年级、状态、标签(标题关键词搜索)
  • 操作编辑、复制生成副本title 加" - 副本"、删除软删除status=archived、发布status=published

6. P1知识点标注与关联

6.1 手动标注

  • 在富文本类 block 内选中文本 → 弹出知识点选择器(从 textbooks 模块的章节-知识点树勾选)
  • 选中的 knowledgePointId 写入该 block 的 data.knowledgePointIds
  • block 渲染时在关联的知识点旁显示标签 chip

6.2 AI 推荐轻量P1 不做完整 AI 课案生成)

  • 编辑器顶部"AI 推荐知识点"按钮 → 读取当前课案所有 block 的纯文本 → 调用 shared/lib/ai.createAiChatCompletion → 返回推荐 knowledgePointId 列表
  • 教师在弹窗中勾选确认 → 合并到对应 block 的 knowledgePointIds
  • AI 仅做"推荐候选",不自动写入;知识点池来自教材已有知识点(不创建新知识点)

6.3 知识点-课案映射查询data-access 暴露)

  • getLessonPlansByKnowledgePoint(knowledgePointId):反查哪些课案重点讲解了某知识点(供后续学情分析/教材知识点树反查使用P1 仅实现 data-access 函数,不做 UI

7. P1题目创建 / 拉取 / 同步题库

7.1 从题库拉取source=bank

  • exercise block 侧栏:题库搜索器(按知识点 / 题型 / 难度筛选,调用 questions/data-access.getQuestions
  • 选中题目 → 插入 exercise.itemssource=bank, questionId=真实 ID
  • 仅引用,不复制题目内容;渲染时按 questionId 查询展示

7.2 课案内新建题目source=inline

  • exercise block 内"新建题目"按钮 → 弹出题目编辑器(复用 questions/components/create-question-dialog 的表单逻辑)
  • 编辑期:题目暂存为 inline draft完整内容存入 exercise.items[].inlineContent(结构与 questions 表字段对齐),questionId 为占位 inline_draft_${cuid}
  • 保存课案时inline 题目不立即入库,保持 draft 状态inlineContent 随课案 content 一起持久化)
  • 发布作业时(见 §8inline 题目先入库(调用 questions/data-access.createQuestionWithRelations,入参取自 inlineContent用真实 questionId 替换占位 ID回写到课案 content

7.3 题目-课案关联查询

  • getLessonPlansByQuestion(questionId):反查某题在哪些课案的哪个 exercise block 被使用data-access 函数P1 仅实现,不做 UI

8. P1作业 / 考试发布打通(复用 exam 中转)

8.1 发布流程

教师点击 exercise blockpurpose=after_class_homework的"发布作业"按钮
  │
  ▼
[Action] publishLessonPlanHomeworkAction
  │
  ├─ requirePermission(LESSON_PLAN_PUBLISH)
  │
  ├─ 1. inline 题目入库
  │     └─ 遍历 exercise.items对 source=inline 的调用
  │        questions/data-access.createQuestionWithRelations
  │        authorId=教师,关联 knowledgePointIds
  │     └─ 用真实 questionId 替换课案 content 中的占位 ID
  │     └─ 更新 lesson_plans.content
  │
  ├─ 2. 打包成 exam 草稿
  │     └─ 调用 exams/data-access.persistExamDraft
  │        title=课案标题+" - 作业"creatorId=教师,
  │         sourceLessonPlanId=课案ID关联 textbookId/chapterId/subjectId/gradeId
  │         examQuestions = exercise.items 映射)
  │     └─ 得到 examId
  │
  ├─ 3. 下发作业
  │     └─ 调用 homework/data-access-write.createHomeworkAssignment
  │        sourceExamId=examId, title, targets=班级学生列表,
  │         availableAt, dueAt
  │     └─ 得到 assignmentId
  │
  ├─ 4. 记录溯源
  │     └─ 在课案 content 的 exercise block.data 写入
  │        publishedAssignmentId + publishedExamId + publishedAt
  │
  └─ revalidatePath("/teacher/lesson-plans") + revalidatePath("/teacher/homework")

8.2 溯源标记

  • 课案 exercise block 渲染时:若 data.publishedAssignmentId 存在,显示"已发布为作业"徽章 + 跳转链接
  • 作业侧P1 不改 homework 模块):作业的 sourceExamId → exam → 可查到 sourceLessonPlanIdexam 草稿创建时记录),实现"作业→课案"反查链路
  • 学情报告P3通过 assignmentId → exam → lessonPlanId 回链到课案

8.3 发布前置校验

  • exercise block 至少有 1 道题
  • inline 题目必须填写完整content/type/difficulty/knowledgePointIds
  • 教师必须对目标班级有 class_taught DataScope 权限
  • 同一 exercise block 不可重复发布(已有 publishedAssignmentId 则禁用发布按钮,提供"重新发布为新作业"选项)

9. 模块文件结构

src/modules/lesson-preparation/
├─ actions.ts                    # Server Actions编排层
├─ data-access.ts                # 课案 CRUD + 版本查询
├─ data-access-versions.ts       # 版本快照写入 + 查询 + 回退
├─ data-access-templates.ts      # 模板 CRUDsystem + personal
├─ data-access-knowledge.ts      # 知识点-课案映射查询P1
├─ publish-service.ts            # 发布编排inline 入库 → exam 草稿 → 作业下发)
├─ ai-suggest.ts                 # AI 知识点推荐P1 轻量)
├─ schema.ts                     # Zod 验证
├─ types.ts                      # 类型定义(含 Block 类型联合)
├─ constants.ts                  # 模板预设、block 类型枚举、状态常量
├─ seed.ts                       # 系统预设模板 seed 脚本
├─ hooks/
│  └─ use-lesson-plan-editor.ts  # 编辑器状态管理(自动保存/版本/拖拽)
└─ components/
   ├─ lesson-plan-list.tsx              # 我的课案库列表
   ├─ lesson-plan-card.tsx              # 课案卡片
   ├─ lesson-plan-filters.tsx           # 筛选器
   ├─ lesson-plan-editor.tsx            # 编辑器主壳block 列表容器)
   ├─ block-renderer.tsx                # block 分发渲染
   ├─ blocks/
   │  ├─ rich-text-block.tsx            # 富文本类 block 编辑器
   │  ├─ text-study-block.tsx           # 文本研习画布 block
   │  ├─ exercise-block.tsx             # 练习/作业 block
   │  └─ reflection-block.tsx           # 教学反思P3 预留P1 简单渲染)
   ├─ template-picker.tsx               # 模板选择器
   ├─ version-history-drawer.tsx        # 版本历史抽屉
   ├─ knowledge-point-picker.tsx        # 知识点选择器(复用 textbooks 组件)
   ├─ question-bank-picker.tsx          # 题库拉取侧栏(复用 questions 组件)
   ├─ inline-question-editor.tsx        # 课案内新建题目(复用 questions 表单)
   └─ publish-homework-dialog.tsx       # 发布作业弹窗(选班级/时间)

10. Server Actions 清单

所有 Action 遵循项目规范:requirePermission() → Zod 校验 → 调用 data-access → revalidatePath → 返回 ActionState<T>

Action 权限点 用途
getLessonPlansAction LESSON_PLAN_READ 我的课案库列表(含筛选)
getLessonPlanByIdAction LESSON_PLAN_READ 获取单个课案含权限校验creator 或 published
createLessonPlanAction LESSON_PLAN_CREATE 创建课案(选模板 → 生成初始 content
updateLessonPlanAction LESSON_PLAN_UPDATE 更新课案(自动保存,不生成版本)
saveLessonPlanVersionAction LESSON_PLAN_UPDATE 手动保存生成版本
revertLessonPlanVersionAction LESSON_PLAN_UPDATE 回退到指定版本(生成新版本)
getLessonPlanVersionsAction LESSON_PLAN_READ 获取版本列表
deleteLessonPlanAction LESSON_PLAN_DELETE 删除课案软删除status=archived
duplicateLessonPlanAction LESSON_PLAN_CREATE 复制课案
getLessonPlanTemplatesAction LESSON_PLAN_READ 获取模板列表system + 我的 personal
saveAsTemplateAction LESSON_PLAN_CREATE 另存为我的模板
deleteTemplateAction LESSON_PLAN_DELETE 删除 personal 模板
suggestKnowledgePointsAction LESSON_PLAN_READ + AI_CHAT AI 推荐知识点(只读返回候选,不写入课案;教师确认后另调 updateLessonPlanAction
publishLessonPlanHomeworkAction LESSON_PLAN_PUBLISH + HOMEWORK_CREATE 发布作业§8 编排)

11. data-access 清单

函数 用途
getLessonPlans(params & scope) 课案列表DataScope 过滤)
getLessonPlanById(id, scope) 单课案详情
createLessonPlan(input) 创建(含模板初始化 content
updateLessonPlanContent(id, content, userId) 更新 content + lastSavedAt自动保存
softDeleteLessonPlan(id, userId) status=archived
duplicateLessonPlan(id, userId) 复制
getLessonPlanVersions(planId) 版本列表
createLessonPlanVersion(planId, content, userId, isAuto, label?) 写版本快照
revertToVersion(planId, versionNo, userId) 用版本 content 覆盖当前 + 生成新版本
pruneAutoVersions(planId, keep=50) 清理超出上限的自动版本
getLessonPlanTemplates(userId) system + 该用户 personal
createPersonalTemplate(input, userId) 创建 personal 模板
deletePersonalTemplate(id, userId) 删除(仅 owner
getLessonPlansByKnowledgePoint(kpId) 知识点反查课案P1 data-access only
getLessonPlansByQuestion(questionId) 题目反查课案P1 data-access only

12. 权限点(新增 5 个)

src/shared/types/permissions.ts 新增:

// Lesson Plan (备课)
LESSON_PLAN_CREATE: "lesson_plan:create",
LESSON_PLAN_READ: "lesson_plan:read",
LESSON_PLAN_UPDATE: "lesson_plan:update",
LESSON_PLAN_DELETE: "lesson_plan:delete",
LESSON_PLAN_PUBLISH: "lesson_plan:publish",

src/shared/lib/permissions.tsROLE_PERMISSIONS 映射中:

  • teacher:全部 5 个
  • admin:全部 5 个
  • student/parent/其他:无

13. 路由

路由 页面 权限
/teacher/lesson-plans 我的课案库列表 LESSON_PLAN_READ
/teacher/lesson-plans/new 新建课案(选模板) LESSON_PLAN_CREATE
/teacher/lesson-plans/[planId]/edit 课案编辑器 LESSON_PLAN_UPDATEcreator或 LESSON_PLAN_READpublished 只读)

侧边栏导航:在 layout/config/navigation.ts 的 teacher 角色菜单新增"备课"项。


14. DataScope 接入

  • getLessonPlans 接受 scope 参数:
    • teacher/admintype=all 或 class_taught返回自己创建的 + 公开 published 的
    • 其他角色:仅 published 的
  • getLessonPlanByIdcreator 可看自己的 draft非 creator 仅当 status=published 可看
  • 写操作update/delete/publish仅 creatorDataScope 不适用,直接校验 creatorId === userId

15. 架构图同步计划

按项目规则"改码必同步图",实现完成后需更新:

15.1 docs/architecture/004_architecture_impact_map.md

  • §1.1 分层架构图modules 行新增 lesson-preparation
  • §1.2 模块依赖关系图:新增 lesson-preparation 节点,标注对 textbooks/questions/exams/homework/classes/files 的合理依赖(───▶ data-access
  • 第二部分新增 §2.27 lesson-preparation 模块清单(职责/导出函数/依赖/文件清单)
  • 附录 A 依赖矩阵新增一行一列

15.2 docs/architecture/005_architecture_data.json

  • modules.lesson_preparation:完整模块节点
  • dbTables:新增 lesson_plans / lesson_plan_versions / lesson_plan_templates
  • permissions:新增 5 个权限点
  • routes:新增 3 个路由
  • dependencyMatrix:新增依赖关系

15.3 src/shared/db/schema.ts

新增 3 张表定义(按现有分节风格,加在合适 section。schema.ts 当前 1111 行已超 1000 硬上限P0 已知问题),新增 3 表会加剧;建议本次新增时一并按业务域拆分 schema.ts但拆分属独立任务不在本 spec 范围,仅在备注中提示)。


16. 实施分阶段计划

P0 地基(先做)

  1. 新增 3 张表 schema + 迁移
  2. 新增 5 个权限点 + 角色映射
  3. seed 系统预设模板4+1 套)
  4. data-access + data-access-versions + data-access-templates
  5. 基础 CRUD Actionscreate/get/update/delete/duplicate
  6. 版本管理 Actionssave version / revert / list
  7. 模板 Actionslist / save as / delete
  8. 我的课案库列表页 + 筛选
  9. Block 编辑器主壳 + 富文本类 block + 拖拽排序 + 自动保存
  10. 版本历史抽屉
  11. 模板选择器(新建课案入口)
  12. 路由 + 侧边栏导航
  13. 同步架构图 004/005

P1 联动P0 完成后)

  1. text_study block设计稿画布形态
  2. exercise block + 题库拉取侧栏source=bank
  3. exercise block + 课案内新建题目source=inlinedraft 暂存)
  4. 知识点选择器 + block 内 knowledgePointIds 标注
  5. AI 知识点推荐 Action + 编辑器入口
  6. publish-serviceinline 入库 → exam 草稿 → 作业下发)
  7. 发布作业弹窗(选班级/时间)
  8. 溯源标记渲染(已发布徽章 + 跳转)
  9. data-access-knowledge反查函数无 UI
  10. 同步架构图(若 P1 新增了导出函数)

17. 验收标准

P0 验收

  • 教师可创建课案(选教材/章节/模板)
  • 5 套系统预设模板可选,选用后生成对应 block 骨架
  • Block 编辑器:增删改 block、拖拽排序、富文本编辑
  • 自动保存3s debounce+ 手动保存生成版本
  • 版本历史:列表、预览、回退
  • 我的课案库:列表、筛选、复制、删除
  • 权限校验:非 creator 无法编辑 draft
  • npm run lint + npx tsc --noEmit 零错误
  • 架构图 004/005 已同步

P1 验收

  • exercise block 可从题库拉取题目并展示
  • exercise block 可课案内新建题目draft 暂存)
  • 富文本 block 可标注知识点(选择器 + chip 展示)
  • AI 推荐知识点按钮可用,推荐结果可勾选确认
  • exercise blockpurpose=after_class_homework可发布为作业
  • 发布后 inline 题目已入库,课案 content 中占位 ID 已替换
  • 发布后作业可通过 sourceExamId → exam → sourceLessonPlanId 反查课案
  • 已发布 exercise block 显示溯源徽章
  • 重复发布被拦截(提供"重新发布为新作业"
  • npm run lint + npx tsc --noEmit 零错误
  • 架构图已同步

18. 未覆盖范围P2/P3 预告,本次不实现)

以下功能在蓝图中提及,但不在本 spec 范围,留作后续独立 spec

P2 协作

  • 分享链接(密码/有效期)
  • block 级批注线程(依赖本 spec 的稳定 blockId
  • 采纳建议生成新版本

P3 智能与回看

  • AI 课案初稿生成(按模板结构填充)
  • 环节级 AI 重写(选中 block → 指令 → 替换该 block
  • 一致性检查(目标-活动-评价对齐)
  • 系统内资源推荐(微课/课件/实验视频)
  • 外部资源对接(国家中小学智慧教育平台 API
  • AI 生成资源草稿(课件大纲/微课脚本/学案)
  • 教学反思 block 完整 UI
  • 学情回看(班级知识点掌握率/高频错题内嵌)
  • AI 补救教学建议
  • 知识点回写教材树(含审核流)

19. 风险与备注

风险 影响 缓解
schema.ts 已 1111 行超 1000 硬上限,新增 3 表加剧 违反编码规范 本次新增时备注提示schema.ts 按业务域拆分作为独立任务跟进
Block 编辑器复杂度高 P0 工期风险 优先用成熟库(如 BlockNote/Plate二次封装不自研底层
inline 题目发布时入库失败 数据不一致 publish-service 用事务包裹;失败则回滚 exam 草稿创建,课案 content 不替换占位 ID
自动保存频率高导致 versions 表膨胀 存储压力 自动保存不写 versions定时自动版本 30min 一次pruneAutoVersions 保留上限 50
AI 推荐知识点依赖 AI Provider 配置 功能可用性 AI 不可用时按钮置灰 + 提示"未配置 AI Provider";不阻塞主流程

本 spec 完成后,下一步进入 writing-plans skill 生成详细实施计划。