系统架构

数据库设计

EduBuddy 使用 SQLite 作为嵌入式数据库,共包含 13 张数据表,采用 UUID(TEXT 类型)作为主键,启用 WAL 模式和外键约束。

数据库配置

-- 启用 WAL 模式(Write-Ahead Logging)
PRAGMA journal_mode = WAL;

-- 启用外键约束
PRAGMA foreign_keys = ON;

表关系图

users (用户) ├── learning_paths (学习路线) [created_by → users.id] │ └── learning_path_nodes (路线节点) [path_id → learning_paths.id] │ └── user_learning_paths (用户报名) [user_id → users.id, path_id → learning_paths.id] │ ├── questions (题目) [created_by → users.id] │ ├── practice_records (练习记录) [user_id → users.id, question_id → questions.id] │ └── quizzes (测验) [created_by → users.id] │ └── quiz_records (测验记录) [user_id → users.id, quiz_id → quizzes.id] │ ├── knowledge_mastery (知识点掌握度) [user_id → users.id] ├── learning_goals (学习目标) [user_id → users.id] ├── study_suggestions (学习建议) [user_id → users.id] ├── file_uploads (文件上传) [user_id → users.id] ├── user_shares (资源分享) [from_user_id → users.id, to_user_id → users.id] ├── notes (笔记) [user_id → users.id] └── daily_stats (每日统计) [user_id → users.id]

核心数据表详解

users — 用户表

字段类型说明
idTEXT PKUUID v4
usernameTEXT UNIQUE登录用户名
emailTEXT UNIQUE邮箱
password_hashTEXTbcrypt 哈希(cost=12)
display_nameTEXT显示名称
roleTEXTstudent / teacher / admin
gradeTEXT年级(可选)
subjectsTEXTJSON 数组,学习科目列表
is_activeINTEGER1=启用,0=禁用(软删除)
last_loginDATETIME最后登录时间

questions — 题目表

字段类型说明
idTEXT PKUUID v4
titleTEXT题目简标题
contentTEXT题目完整内容
subjectTEXT科目(数学/物理/英语等)
gradeTEXT适用年级(可选)
topicTEXT知识点标签
difficultyTEXTeasy / medium / hard
question_typeTEXTmultiple_choice / fill_blank / short_answer / essay / calculation
optionsTEXTJSON 数组(选择题选项)
correct_answerTEXT正确答案
explanationTEXT解题说明(Markdown)
is_publicINTEGER1=公开,0=私有
created_byTEXT FK→ users.id

practice_records — 练习记录表

字段类型说明
idTEXT PKUUID v4
user_idTEXT FK→ users.id
question_idTEXT FK→ questions.id
user_answerTEXT学生提交的答案
is_correctINTEGER1=正确,0=错误
scoreREALAI 评分(0-100)
feedbackTEXTAI 批改反馈
time_spentINTEGER答题用时(秒)
practiced_atDATETIME答题时间

knowledge_mastery — 知识点掌握度表

字段类型说明
idTEXT PKUUID v4
user_idTEXT FK→ users.id
subjectTEXT科目
topicTEXT知识点名称
mastery_levelREAL掌握度 0-100
practice_countINTEGER累计练习次数
correct_countINTEGER答对次数
唯一约束:(user_id, subject, topic)

learning_paths — 学习路线表

字段类型说明
idTEXT PKUUID v4
titleTEXT路线标题
subjectTEXT科目
gradeTEXT适用年级
difficultyTEXTbeginner / intermediate / advanced
estimated_hoursINTEGER预计学时(小时)
is_publicINTEGER1=公开
created_byTEXT FK→ users.id

daily_stats — 每日学习统计表

字段类型说明
user_idTEXT FK→ users.id
dateTEXT日期(YYYY-MM-DD)
study_minutesINTEGER当日学习分钟数
questions_practicedINTEGER当日练习题数
correct_answersINTEGER当日答对数
avg_scoreREAL当日平均分
唯一约束:(user_id, date)

数据库索引

-- 练习记录按用户查询(高频)
CREATE INDEX idx_practice_records_user ON practice_records(user_id);

-- 练习记录按题目查询
CREATE INDEX idx_practice_records_question ON practice_records(question_id);

-- 知识点掌握度按用户查询(高频)
CREATE INDEX idx_knowledge_mastery_user ON knowledge_mastery(user_id);

-- 题目按科目筛选(高频)
CREATE INDEX idx_questions_subject ON questions(subject);

-- 每日统计按用户+日期查询(高频)
CREATE INDEX idx_daily_stats_user_date ON daily_stats(user_id, date);

-- 测验记录按用户查询
CREATE INDEX idx_quiz_records_user ON quiz_records(user_id);

JSON 字段说明

SQLite 不原生支持数组/JSON 类型,以下字段使用 TEXT 存储 JSON 字符串:

表.字段JSON 结构示例
users.subjects字符串数组["数学","物理"]
questions.options字符串数组(选择题)["A. 选项1","B. 选项2","C. 选项3","D. 选项4"]
questions.tags字符串数组["一元二次方程","因式分解"]
learning_path_nodes.prerequisites节点 ID 数组["node-id-1","node-id-2"]
learning_path_nodes.resources资源字符串数组["《高中数学》第3章","https://..."]
quiz_records.answers答案对象数组[{"questionId":"...","answer":"A"}]
daily_stats.topics_studied知识点字符串数组["二次方程","函数"]
在应用层读取这些字段时,需要调用 JSON.parse();写入时调用 JSON.stringify()。路由代码中已统一处理。

数据库备份

# 直接复制数据库文件(需确保没有写操作)
cp ./data/edubuddy.db ./backups/edubuddy-$(date +%Y%m%d).db

# 使用 SQLite 在线备份(安全)
sqlite3 ./data/edubuddy.db ".backup ./backups/edubuddy-$(date +%Y%m%d).db"