docs: 补移 AI回答.md 到 docs/
Some checks failed
Deploy API Server / build-and-deploy (push) Failing after 11s
Some checks failed
Deploy API Server / build-and-deploy (push) Failing after 11s
This commit is contained in:
parent
3e653dc1af
commit
4435e4a8ab
1185
BACKEND-PLAN.md
1185
BACKEND-PLAN.md
File diff suppressed because it is too large
Load Diff
@ -1,814 +0,0 @@
|
||||
---
|
||||
source: AI回答.md
|
||||
updated: 2026-05-09
|
||||
---
|
||||
|
||||
# 知习 MySQL 数据库表结构设计
|
||||
|
||||
> 共 27 张表,v0.1 先建 24 张核心表。
|
||||
|
||||
---
|
||||
|
||||
## 通用字段规范
|
||||
|
||||
每张核心表统一使用:
|
||||
|
||||
```sql
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at DATETIME NULL
|
||||
```
|
||||
|
||||
- `id`:内部主键
|
||||
- `created_at`:创建时间
|
||||
- `updated_at`:更新时间
|
||||
- `deleted_at`:软删除
|
||||
|
||||
状态字段统一用 `VARCHAR(32)`,不用 MySQL ENUM。
|
||||
|
||||
---
|
||||
|
||||
## 一、用户与认证表(5 张)
|
||||
|
||||
### 1. users 用户表
|
||||
|
||||
```sql
|
||||
users
|
||||
- id BIGINT UNSIGNED PK
|
||||
- email VARCHAR(255) NULL
|
||||
- nickname VARCHAR(100) NULL
|
||||
- avatar_url VARCHAR(500) NULL
|
||||
- status VARCHAR(32) NOT NULL DEFAULT 'active'
|
||||
- onboarding_completed TINYINT(1) NOT NULL DEFAULT 0
|
||||
- last_login_at DATETIME NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
- deleted_at DATETIME NULL
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_users_email (email)
|
||||
INDEX idx_users_status (status)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. auth_accounts 第三方登录账号表
|
||||
|
||||
```sql
|
||||
auth_accounts
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- provider VARCHAR(32) NOT NULL -- apple
|
||||
- provider_user_id VARCHAR(255) NOT NULL -- Apple userIdentifier / sub
|
||||
- email VARCHAR(255) NULL
|
||||
- raw_profile_json JSON NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
UNIQUE KEY uk_provider_user (provider, provider_user_id)
|
||||
INDEX idx_auth_accounts_user_id (user_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. refresh_tokens 刷新 Token 表
|
||||
|
||||
```sql
|
||||
refresh_tokens
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- token_hash VARCHAR(255) NOT NULL
|
||||
- device_id VARCHAR(255) NULL
|
||||
- device_name VARCHAR(255) NULL
|
||||
- expires_at DATETIME NOT NULL
|
||||
- revoked_at DATETIME NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_refresh_tokens_user_id (user_id)
|
||||
INDEX idx_refresh_tokens_token_hash (token_hash)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. user_profiles 用户资料扩展表
|
||||
|
||||
```sql
|
||||
user_profiles
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- learning_identity VARCHAR(100) NULL -- 系统学习者 / 备考用户 / 知识工作者
|
||||
- learning_direction VARCHAR(255) NULL -- 认知科学 / AIGC / 产品设计
|
||||
- bio TEXT NULL
|
||||
- current_goal VARCHAR(255) NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
UNIQUE KEY uk_user_profiles_user_id (user_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. user_preferences 用户学习偏好表
|
||||
|
||||
```sql
|
||||
user_preferences
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- preferred_methods JSON NULL
|
||||
-- ["active_recall", "spaced_repetition", "feynman", "retrieval_practice"]
|
||||
- default_focus_minutes INT NOT NULL DEFAULT 25
|
||||
- ai_suggestion_level VARCHAR(32) NOT NULL DEFAULT 'normal'
|
||||
-- low / normal / high
|
||||
- language VARCHAR(32) NOT NULL DEFAULT 'zh-CN'
|
||||
- appearance VARCHAR(32) NOT NULL DEFAULT 'system'
|
||||
- notification_enabled TINYINT(1) NOT NULL DEFAULT 1
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
UNIQUE KEY uk_user_preferences_user_id (user_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、知识库相关表(5 张)
|
||||
|
||||
### 6. knowledge_bases 知识库表
|
||||
|
||||
```sql
|
||||
knowledge_bases
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- title VARCHAR(255) NOT NULL
|
||||
- description TEXT NULL
|
||||
- cover_key VARCHAR(100) NULL
|
||||
- status VARCHAR(32) NOT NULL DEFAULT 'active'
|
||||
-- active / archived / deleted
|
||||
- item_count INT NOT NULL DEFAULT 0
|
||||
- last_studied_at DATETIME NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
- deleted_at DATETIME NULL
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_knowledge_bases_user_id (user_id)
|
||||
INDEX idx_knowledge_bases_status (status)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. knowledge_items 知识点/内容表
|
||||
|
||||
```sql
|
||||
knowledge_items
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- knowledge_base_id BIGINT UNSIGNED NOT NULL
|
||||
- parent_id BIGINT UNSIGNED NULL
|
||||
- item_type VARCHAR(32) NOT NULL
|
||||
-- chapter / lesson / concept / note / imported_doc
|
||||
- title VARCHAR(255) NOT NULL
|
||||
- content LONGTEXT NULL
|
||||
- summary TEXT NULL
|
||||
- source_type VARCHAR(32) NULL
|
||||
-- manual / file / url / ai_generated
|
||||
- source_ref VARCHAR(500) NULL
|
||||
- order_index INT NOT NULL DEFAULT 0
|
||||
- status VARCHAR(32) NOT NULL DEFAULT 'active'
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
- deleted_at DATETIME NULL
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_knowledge_items_user_id (user_id)
|
||||
INDEX idx_knowledge_items_kb_id (knowledge_base_id)
|
||||
INDEX idx_knowledge_items_parent_id (parent_id)
|
||||
INDEX idx_knowledge_items_type (item_type)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. knowledge_item_relations 知识点关联表
|
||||
|
||||
```sql
|
||||
knowledge_item_relations
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- source_item_id BIGINT UNSIGNED NOT NULL
|
||||
- target_item_id BIGINT UNSIGNED NOT NULL
|
||||
- relation_type VARCHAR(32) NOT NULL
|
||||
-- related / prerequisite / similar / conflict / extension
|
||||
- confidence DECIMAL(5,2) NULL
|
||||
- reason TEXT NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_relations_source (source_item_id)
|
||||
INDEX idx_relations_target (target_item_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9. tags 标签表
|
||||
|
||||
```sql
|
||||
tags
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- name VARCHAR(100) NOT NULL
|
||||
- color VARCHAR(32) NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
UNIQUE KEY uk_user_tag_name (user_id, name)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 10. knowledge_item_tags 知识点标签关联表
|
||||
|
||||
```sql
|
||||
knowledge_item_tags
|
||||
- id BIGINT UNSIGNED PK
|
||||
- knowledge_item_id BIGINT UNSIGNED NOT NULL
|
||||
- tag_id BIGINT UNSIGNED NOT NULL
|
||||
- created_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
UNIQUE KEY uk_item_tag (knowledge_item_id, tag_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、资料导入相关表(2 张)
|
||||
|
||||
### 11. uploaded_files 上传文件表
|
||||
|
||||
```sql
|
||||
uploaded_files
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- filename VARCHAR(255) NOT NULL
|
||||
- mime_type VARCHAR(100) NULL
|
||||
- storage_path VARCHAR(500) NOT NULL
|
||||
- size_bytes BIGINT UNSIGNED NOT NULL DEFAULT 0
|
||||
- checksum VARCHAR(255) NULL
|
||||
- created_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_uploaded_files_user_id (user_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 12. document_imports 资料导入任务表
|
||||
|
||||
```sql
|
||||
document_imports
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- knowledge_base_id BIGINT UNSIGNED NULL
|
||||
- file_id BIGINT UNSIGNED NULL
|
||||
- source_type VARCHAR(32) NOT NULL
|
||||
-- file / text / url
|
||||
- source_name VARCHAR(255) NULL
|
||||
- source_url VARCHAR(500) NULL
|
||||
- raw_text LONGTEXT NULL
|
||||
- status VARCHAR(32) NOT NULL DEFAULT 'pending'
|
||||
-- pending / processing / success / failed
|
||||
- progress INT NOT NULL DEFAULT 0
|
||||
- error_message TEXT NULL
|
||||
- result_json JSON NULL
|
||||
- started_at DATETIME NULL
|
||||
- completed_at DATETIME NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_document_imports_user_id (user_id)
|
||||
INDEX idx_document_imports_status (status)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、学习过程相关表(2 张)
|
||||
|
||||
### 13. learning_sessions 学习会话表
|
||||
|
||||
```sql
|
||||
learning_sessions
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- knowledge_base_id BIGINT UNSIGNED NULL
|
||||
- knowledge_item_id BIGINT UNSIGNED NULL
|
||||
- mode VARCHAR(32) NOT NULL
|
||||
-- reading / active_recall / review / feynman / free_learning
|
||||
- status VARCHAR(32) NOT NULL DEFAULT 'active'
|
||||
-- active / completed / cancelled
|
||||
- started_at DATETIME NOT NULL
|
||||
- ended_at DATETIME NULL
|
||||
- duration_seconds INT NOT NULL DEFAULT 0
|
||||
- focus_minutes INT NULL
|
||||
- metadata JSON NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_learning_sessions_user_id (user_id)
|
||||
INDEX idx_learning_sessions_item_id (knowledge_item_id)
|
||||
INDEX idx_learning_sessions_started_at (started_at)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 14. learning_records 学习记录表
|
||||
|
||||
类似 GitHub commit log,语义是学习记录。
|
||||
|
||||
```sql
|
||||
learning_records
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- session_id BIGINT UNSIGNED NULL
|
||||
- record_type VARCHAR(32) NOT NULL
|
||||
-- read / active_recall / review / ai_analysis / focus_item_completed
|
||||
- title VARCHAR(255) NOT NULL
|
||||
- description TEXT NULL
|
||||
- duration_seconds INT NOT NULL DEFAULT 0
|
||||
- occurred_at DATETIME NOT NULL
|
||||
- metadata JSON NULL
|
||||
- created_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_learning_records_user_id (user_id)
|
||||
INDEX idx_learning_records_occurred_at (occurred_at)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、主动回忆相关表(2 张)
|
||||
|
||||
### 15. active_recall_questions 主动回忆问题表
|
||||
|
||||
```sql
|
||||
active_recall_questions
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- knowledge_item_id BIGINT UNSIGNED NULL
|
||||
- question_text TEXT NOT NULL
|
||||
- difficulty VARCHAR(32) NULL
|
||||
-- easy / normal / hard
|
||||
- created_by VARCHAR(32) NOT NULL DEFAULT 'ai'
|
||||
-- ai / user / system
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_recall_questions_user_id (user_id)
|
||||
INDEX idx_recall_questions_item_id (knowledge_item_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 16. active_recall_answers 主动回忆回答表
|
||||
|
||||
```sql
|
||||
active_recall_answers
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- question_id BIGINT UNSIGNED NULL
|
||||
- session_id BIGINT UNSIGNED NULL
|
||||
- answer_type VARCHAR(32) NOT NULL DEFAULT 'text'
|
||||
-- text / voice
|
||||
- answer_text LONGTEXT NULL
|
||||
- audio_file_id BIGINT UNSIGNED NULL
|
||||
- submitted_at DATETIME NOT NULL
|
||||
- created_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_recall_answers_user_id (user_id)
|
||||
INDEX idx_recall_answers_question_id (question_id)
|
||||
INDEX idx_recall_answers_session_id (session_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、AI 分析相关表(2 张)
|
||||
|
||||
### 17. ai_analysis_jobs AI 分析任务表
|
||||
|
||||
```sql
|
||||
ai_analysis_jobs
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- session_id BIGINT UNSIGNED NULL
|
||||
- answer_id BIGINT UNSIGNED NULL
|
||||
- job_type VARCHAR(32) NOT NULL
|
||||
-- active_recall_analysis / weak_point_detection / review_generation
|
||||
- status VARCHAR(32) NOT NULL DEFAULT 'pending'
|
||||
-- pending / processing / success / failed
|
||||
- progress INT NOT NULL DEFAULT 0
|
||||
- error_message TEXT NULL
|
||||
- queued_at DATETIME NULL
|
||||
- started_at DATETIME NULL
|
||||
- completed_at DATETIME NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_ai_jobs_user_id (user_id)
|
||||
INDEX idx_ai_jobs_status (status)
|
||||
INDEX idx_ai_jobs_session_id (session_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 18. ai_analysis_results AI 分析结果表
|
||||
|
||||
```sql
|
||||
ai_analysis_results
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- job_id BIGINT UNSIGNED NOT NULL
|
||||
- session_id BIGINT UNSIGNED NULL
|
||||
- answer_id BIGINT UNSIGNED NULL
|
||||
- summary TEXT NULL
|
||||
- mastery_score INT NULL -- 0-100
|
||||
- strengths JSON NULL
|
||||
- weaknesses JSON NULL
|
||||
- suggestions JSON NULL
|
||||
- next_actions JSON NULL
|
||||
- raw_result JSON NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_ai_results_user_id (user_id)
|
||||
INDEX idx_ai_results_job_id (job_id)
|
||||
INDEX idx_ai_results_session_id (session_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、待巩固项表(1 张)
|
||||
|
||||
### 19. focus_items 待巩固项表
|
||||
|
||||
类似 GitHub issue,学习语义叫「待巩固项」。
|
||||
|
||||
```sql
|
||||
focus_items
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- knowledge_base_id BIGINT UNSIGNED NULL
|
||||
- knowledge_item_id BIGINT UNSIGNED NULL
|
||||
- analysis_result_id BIGINT UNSIGNED NULL
|
||||
- title VARCHAR(255) NOT NULL
|
||||
- reason TEXT NULL
|
||||
- suggestion TEXT NULL
|
||||
- priority VARCHAR(32) NOT NULL DEFAULT 'normal'
|
||||
-- low / normal / high
|
||||
- status VARCHAR(32) NOT NULL DEFAULT 'open'
|
||||
-- open / in_review / completed / ignored
|
||||
- mastery_score INT NULL
|
||||
- due_at DATETIME NULL
|
||||
- completed_at DATETIME NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
- deleted_at DATETIME NULL
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_focus_items_user_id (user_id)
|
||||
INDEX idx_focus_items_status (status)
|
||||
INDEX idx_focus_items_due_at (due_at)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、复习相关表(3 张)
|
||||
|
||||
### 20. review_cards 复习卡片表
|
||||
|
||||
```sql
|
||||
review_cards
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- knowledge_item_id BIGINT UNSIGNED NULL
|
||||
- focus_item_id BIGINT UNSIGNED NULL
|
||||
- front_text TEXT NOT NULL
|
||||
- back_text TEXT NULL
|
||||
- difficulty VARCHAR(32) NULL
|
||||
- status VARCHAR(32) NOT NULL DEFAULT 'active'
|
||||
-- active / suspended / completed
|
||||
- next_review_at DATETIME NULL
|
||||
- interval_days INT NOT NULL DEFAULT 1
|
||||
- ease_factor DECIMAL(4,2) NOT NULL DEFAULT 2.50
|
||||
- repetition_count INT NOT NULL DEFAULT 0
|
||||
- lapse_count INT NOT NULL DEFAULT 0
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
- deleted_at DATETIME NULL
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_review_cards_user_id (user_id)
|
||||
INDEX idx_review_cards_next_review_at (next_review_at)
|
||||
INDEX idx_review_cards_focus_item_id (focus_item_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 21. review_logs 复习记录表
|
||||
|
||||
```sql
|
||||
review_logs
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- review_card_id BIGINT UNSIGNED NOT NULL
|
||||
- session_id BIGINT UNSIGNED NULL
|
||||
- rating VARCHAR(32) NOT NULL
|
||||
-- again / hard / good / easy
|
||||
- response_text TEXT NULL
|
||||
- reviewed_at DATETIME NOT NULL
|
||||
- next_review_at DATETIME NULL
|
||||
- created_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_review_logs_user_id (user_id)
|
||||
INDEX idx_review_logs_card_id (review_card_id)
|
||||
INDEX idx_review_logs_reviewed_at (reviewed_at)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 22. review_plans 复习计划表
|
||||
|
||||
```sql
|
||||
review_plans
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- title VARCHAR(255) NOT NULL
|
||||
- status VARCHAR(32) NOT NULL DEFAULT 'active'
|
||||
-- active / completed / cancelled
|
||||
- scheduled_at DATETIME NULL
|
||||
- completed_at DATETIME NULL
|
||||
- card_count INT NOT NULL DEFAULT 0
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_review_plans_user_id (user_id)
|
||||
INDEX idx_review_plans_scheduled_at (scheduled_at)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、学习活跃记录表(1 张)
|
||||
|
||||
### 23. daily_learning_activities 每日学习活跃表
|
||||
|
||||
用于个人中心的蓝色学习活跃图。
|
||||
|
||||
```sql
|
||||
daily_learning_activities
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- activity_date DATE NOT NULL
|
||||
- duration_seconds INT NOT NULL DEFAULT 0
|
||||
- sessions_count INT NOT NULL DEFAULT 0
|
||||
- active_recall_count INT NOT NULL DEFAULT 0
|
||||
- review_count INT NOT NULL DEFAULT 0
|
||||
- ai_analysis_count INT NOT NULL DEFAULT 0
|
||||
- completed_loop_count INT NOT NULL DEFAULT 0
|
||||
- activity_level INT NOT NULL DEFAULT 0 -- 0-4,颜色深浅
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
UNIQUE KEY uk_user_activity_date (user_id, activity_date)
|
||||
INDEX idx_daily_activity_user_id (user_id)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、通知与反馈表(2 张)
|
||||
|
||||
### 24. notifications 消息通知表
|
||||
|
||||
```sql
|
||||
notifications
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- type VARCHAR(32) NOT NULL
|
||||
-- review_due / ai_analysis_done / learning_suggestion / system
|
||||
- title VARCHAR(255) NOT NULL
|
||||
- content TEXT NULL
|
||||
- data JSON NULL
|
||||
- read_at DATETIME NULL
|
||||
- created_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_notifications_user_id (user_id)
|
||||
INDEX idx_notifications_read_at (read_at)
|
||||
INDEX idx_notifications_type (type)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 25. feedbacks 用户反馈表
|
||||
|
||||
```sql
|
||||
feedbacks
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NULL
|
||||
- email VARCHAR(255) NULL
|
||||
- category VARCHAR(64) NOT NULL
|
||||
-- feature / bug / experience / privacy / other
|
||||
- content TEXT NOT NULL
|
||||
- device_info JSON NULL
|
||||
- status VARCHAR(32) NOT NULL DEFAULT 'open'
|
||||
-- open / processing / resolved / ignored
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_feedbacks_user_id (user_id)
|
||||
INDEX idx_feedbacks_status (status)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十一、合规与系统表(2 张)
|
||||
|
||||
### 26. user_consents 用户协议同意记录表
|
||||
|
||||
```sql
|
||||
user_consents
|
||||
- id BIGINT UNSIGNED PK
|
||||
- user_id BIGINT UNSIGNED NOT NULL
|
||||
- consent_type VARCHAR(32) NOT NULL
|
||||
-- privacy_policy / terms_of_service
|
||||
- version VARCHAR(50) NOT NULL
|
||||
- accepted_at DATETIME NOT NULL
|
||||
- ip_address VARCHAR(100) NULL
|
||||
- user_agent VARCHAR(500) NULL
|
||||
- created_at DATETIME
|
||||
```
|
||||
|
||||
索引:
|
||||
```sql
|
||||
INDEX idx_user_consents_user_id (user_id)
|
||||
INDEX idx_user_consents_type (consent_type)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 27. app_changelogs 更新记录表(可选)
|
||||
|
||||
```sql
|
||||
app_changelogs
|
||||
- id BIGINT UNSIGNED PK
|
||||
- version VARCHAR(50) NOT NULL
|
||||
- title VARCHAR(255) NOT NULL
|
||||
- content TEXT NOT NULL
|
||||
- platform VARCHAR(32) NOT NULL DEFAULT 'ios'
|
||||
- published_at DATETIME NULL
|
||||
- created_at DATETIME
|
||||
- updated_at DATETIME
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## v0.1 建表优先级
|
||||
|
||||
### 第一批(24 张,必须)
|
||||
|
||||
```text
|
||||
users
|
||||
auth_accounts
|
||||
refresh_tokens
|
||||
user_profiles
|
||||
user_preferences
|
||||
|
||||
knowledge_bases
|
||||
knowledge_items
|
||||
tags
|
||||
knowledge_item_tags
|
||||
document_imports
|
||||
uploaded_files
|
||||
|
||||
learning_sessions
|
||||
learning_records
|
||||
active_recall_questions
|
||||
active_recall_answers
|
||||
|
||||
ai_analysis_jobs
|
||||
ai_analysis_results
|
||||
focus_items
|
||||
|
||||
review_cards
|
||||
review_logs
|
||||
|
||||
daily_learning_activities
|
||||
|
||||
notifications
|
||||
feedbacks
|
||||
user_consents
|
||||
```
|
||||
|
||||
### 第二批(3 张,可稍后)
|
||||
|
||||
```text
|
||||
knowledge_item_relations
|
||||
review_plans
|
||||
app_changelogs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 模块与表对应关系
|
||||
|
||||
```text
|
||||
auth → users, auth_accounts, refresh_tokens
|
||||
users → user_profiles, user_preferences, user_consents
|
||||
knowledge-base → knowledge_bases
|
||||
knowledge-items → knowledge_items, knowledge_item_relations, tags, knowledge_item_tags
|
||||
document-import → uploaded_files, document_imports
|
||||
learning-session → learning_sessions, learning_records
|
||||
active-recall → active_recall_questions, active_recall_answers
|
||||
ai-analysis → ai_analysis_jobs, ai_analysis_results
|
||||
focus-items → focus_items
|
||||
review → review_cards, review_logs, review_plans
|
||||
learning-activity → daily_learning_activities
|
||||
notifications → notifications
|
||||
feedback → feedbacks
|
||||
system → app_changelogs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Prisma 生成规范
|
||||
|
||||
```text
|
||||
所有表使用 BIGINT UNSIGNED AUTO_INCREMENT 主键
|
||||
状态字段使用 VARCHAR,不使用 ENUM
|
||||
JSON 字段用于存储 AI 分析结构化结果、用户偏好、元数据
|
||||
核心表添加 created_at、updated_at、deleted_at
|
||||
为 user_id、status、created_at、外键字段添加合理索引
|
||||
```
|
||||
262
REDIS-DESIGN.md
262
REDIS-DESIGN.md
@ -1,262 +0,0 @@
|
||||
---
|
||||
source: AI回答.md
|
||||
updated: 2026-05-09
|
||||
---
|
||||
|
||||
# 知习 Redis 设计
|
||||
|
||||
> Redis 在知习里不是"另一个 MySQL",它是系统的**加速器和调度器**。MySQL 存结果,Redis 管过程。
|
||||
|
||||
---
|
||||
|
||||
## 1. Redis 定位
|
||||
|
||||
Redis 不作为主数据库,只负责:
|
||||
|
||||
1. 缓存
|
||||
2. 限流
|
||||
3. 队列(BullMQ)
|
||||
4. 临时任务状态
|
||||
5. 分布式锁
|
||||
6. 防重复提交
|
||||
7. AI 调用次数统计
|
||||
8. 短期 Token / 黑名单
|
||||
9. 通知任务调度
|
||||
10. 学习会话草稿
|
||||
|
||||
---
|
||||
|
||||
## 2. Key 命名规范
|
||||
|
||||
统一格式:
|
||||
|
||||
```text
|
||||
业务域:对象类型:对象ID:字段
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
cache:user:123:profile
|
||||
rate:user:123:ai:daily:2026-05-09
|
||||
lock:ai-analysis:session:987
|
||||
job:ai-analysis:abc123:status
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
1. 全部小写
|
||||
2. 用冒号 `:` 分隔
|
||||
3. 从大范围到小范围
|
||||
4. userId、jobId、sessionId 明确写在 key 里
|
||||
5. 带日期的 key 用 `YYYY-MM-DD`
|
||||
6. 所有临时 key 必须设置 TTL
|
||||
|
||||
---
|
||||
|
||||
## 3. Key 总表
|
||||
|
||||
### 缓存类
|
||||
|
||||
| Key | 用途 | TTL |
|
||||
|-----|------|-----|
|
||||
| `cache:user:{userId}:profile` | 用户资料 | 5-10 分钟 |
|
||||
| `cache:user:{userId}:preferences` | 用户偏好设置 | 10 分钟 |
|
||||
| `cache:user:{userId}:knowledge-bases` | 用户知识库列表 | 3-5 分钟 |
|
||||
| `cache:knowledge-base:{kbId}:summary` | 知识库摘要 | 5 分钟 |
|
||||
| `cache:review:user:{userId}:due-count` | 到期复习数量 | 1-3 分钟 |
|
||||
|
||||
### 限流类
|
||||
|
||||
| Key | 用途 | TTL |
|
||||
|-----|------|-----|
|
||||
| `rate:user:{userId}:ai:daily:{date}` | 用户每日 AI 调用次数 | 到当天结束或 24h |
|
||||
| `rate:user:{userId}:feedback:hourly` | 用户每小时反馈次数 | 1 小时 |
|
||||
| `rate:ip:{ip}:request:{minute}` | IP 每分钟请求频率 | 60-120 秒 |
|
||||
| `rate:ip:{ip}:login:{date}` | IP 每日登录尝试 | 10-30 分钟 |
|
||||
|
||||
### 分布式锁类
|
||||
|
||||
| Key | 用途 | TTL |
|
||||
|-----|------|-----|
|
||||
| `lock:ai-analysis:session:{sessionId}` | 防止重复提交 AI 分析 | 60-300 秒 |
|
||||
| `lock:ai-analysis:answer:{answerId}` | 防止同回答重复分析 | 60-300 秒 |
|
||||
| `lock:document-import:{importId}` | 防止重复处理导入 | 5-30 分钟 |
|
||||
| `lock:review-plan:user:{userId}:item:{itemId}` | 防止重复生成复习计划 | 60-300 秒 |
|
||||
| `lock:feedback:ip:{ip}` | 防止 IP 刷反馈 | 60-300 秒 |
|
||||
|
||||
### 任务状态类
|
||||
|
||||
| Key | Value 示例 | TTL |
|
||||
|-----|-----------|-----|
|
||||
| `job:ai-analysis:{jobId}:status` | `pending / processing / completed / failed` | 24h |
|
||||
| `job:ai-analysis:{jobId}:progress` | `0-100` | 24h |
|
||||
| `job:ai-analysis:{jobId}:error` | 错误信息字符串 | 24h |
|
||||
| `job:document-import:{importId}:status` | `pending / parsing / chunking / generating / completed / failed` | 24h |
|
||||
| `job:document-import:{importId}:progress` | `0-100` | 24h |
|
||||
| `job:document-import:{importId}:message` | `"正在提取关键知识点"` | 24h |
|
||||
| `job:document-import:{importId}:error` | 错误信息字符串 | 24h |
|
||||
|
||||
### 会话临时状态类
|
||||
|
||||
| Key | 用途 | TTL |
|
||||
|-----|------|-----|
|
||||
| `session:learning:{sessionId}:heartbeat` | 学习会话心跳 | 30 分钟 |
|
||||
| `session:learning:{sessionId}:current-step` | 当前学习步骤 | 2 小时 |
|
||||
| `session:active-recall:{sessionId}:draft` | 回答草稿暂存 | 1-24 小时 |
|
||||
|
||||
### Token / 黑名单
|
||||
|
||||
| Key | 用途 | TTL |
|
||||
|-----|------|-----|
|
||||
| `auth:refresh-token:blacklist:{tokenId}` | 注销后刷新 Token 失效 | 到 token 过期 |
|
||||
| `auth:access-token:blacklist:{jwtId}` | 注销后 JWT 失效 | 到 token 过期 |
|
||||
|
||||
### Set 类(可选)
|
||||
|
||||
| Key | 用途 |
|
||||
|-----|------|
|
||||
| `set:user:{userId}:reviewed-items:{date}` | 当天已复习项去重 |
|
||||
|
||||
---
|
||||
|
||||
## 4. Redis 数据类型选择
|
||||
|
||||
| 类型 | 用途 | 示例 |
|
||||
|------|------|------|
|
||||
| **String** | 最常用:缓存 JSON、计数器、状态、锁 | `rate:user:123:ai:daily:2026-05-09 = 8` |
|
||||
| **Hash** | 可选,任务多字段频繁更新的场景 | `job:ai-analysis:1001 → status=processing, progress=40` |
|
||||
| **List/Stream** | 队列,BullMQ 自动管理,不需要手动操作 | - |
|
||||
| **Set** | 去重,如当天已复习项集合 | `set:user:123:reviewed-items:2026-05-09` |
|
||||
| **Sorted Set** | 后期按时间排序的复习调度,v0.1 先不做 | - |
|
||||
|
||||
---
|
||||
|
||||
## 5. 核心流程中 Redis 与 MySQL 的配合
|
||||
|
||||
### 5.1 AI 分析流程
|
||||
|
||||
```text
|
||||
1. MySQL 创建 ai_analysis_jobs
|
||||
2. Redis 加入 ai-analysis 队列(BullMQ)
|
||||
3. Redis 存 job:xxx:status = processing
|
||||
4. Worker 调用 AI
|
||||
5. MySQL 写 ai_analysis_results
|
||||
6. MySQL 写 focus_items
|
||||
7. MySQL 写 review_cards
|
||||
8. Redis 存 job:xxx:status = completed
|
||||
9. MySQL 写 notifications
|
||||
```
|
||||
|
||||
### 5.2 资料导入流程
|
||||
|
||||
```text
|
||||
1. MySQL 创建 document_imports
|
||||
2. Redis 加入 document-import 队列(BullMQ)
|
||||
3. Redis 存导入进度
|
||||
4. Worker 解析文件
|
||||
5. MySQL 写 knowledge_items
|
||||
6. MySQL 更新 document_imports 为 success
|
||||
7. Redis 存状态 completed
|
||||
```
|
||||
|
||||
### 5.3 学习活跃图流程
|
||||
|
||||
```text
|
||||
1. 用户完成学习动作
|
||||
2. MySQL 写 learning_records
|
||||
3. MySQL 更新 daily_learning_activities
|
||||
4. Redis 可短期缓存今日活跃统计
|
||||
5. App 查询活跃图优先查 MySQL,必要时加缓存
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. BullMQ 队列
|
||||
|
||||
BullMQ 自动管理 Redis key,不需要手动建。建议预留 3 个队列:
|
||||
|
||||
| 队列名 | 任务数据 | 处理逻辑 |
|
||||
|--------|---------|---------|
|
||||
| `ai-analysis` | `{ jobId, userId, sessionId, answerId, jobType }` | 读取回答 → 调 AI → 写结果 → 生成待巩固项 → 生成复习卡片 → 发通知 |
|
||||
| `document-import` | `{ importId, userId, knowledgeBaseId, sourceType }` | 解析文件 → 提取文本 → 分段 → 生成知识点 → 写 knowledge_items → 更新状态 |
|
||||
| `notification` | `{ userId, type, title, data }` | 写 notifications 表,后续可扩展 APNs 推送 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 哪些绝对不能只放 Redis
|
||||
|
||||
以下全部必须写 MySQL,Redis 只能做缓存,不是唯一来源:
|
||||
|
||||
```text
|
||||
用户资料 → users, user_profiles
|
||||
知识库内容 → knowledge_bases
|
||||
知识点内容 → knowledge_items
|
||||
学习记录 → learning_records
|
||||
主动回忆回答 → active_recall_answers
|
||||
AI 分析结果 → ai_analysis_results
|
||||
待巩固项 → focus_items
|
||||
复习卡片 → review_cards
|
||||
复习记录 → review_logs
|
||||
学习活跃记录 → daily_learning_activities
|
||||
通知记录 → notifications
|
||||
用户设置 → user_preferences
|
||||
协议同意记录 → user_consents
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. v0.1 Redis 最小落地范围
|
||||
|
||||
### 必须做
|
||||
|
||||
```text
|
||||
1. Redis 连接
|
||||
2. /health 检查 Redis
|
||||
3. RedisModule + RedisService(get/set/del/exists/expire/ttl/incr/setNx/lock/unlock)
|
||||
4. AI 每日调用限流(rate:user:{userId}:ai:daily:{date})
|
||||
5. AI 分析队列(BullMQ ai-analysis)
|
||||
6. AI 分析任务状态(job:ai-analysis:{jobId}:status/progress/error)
|
||||
7. 防重复提交锁(lock:ai-analysis:session:{sessionId})
|
||||
8. document-import 队列预留(BullMQ document-import)
|
||||
9. notification 队列预留(BullMQ notification)
|
||||
```
|
||||
|
||||
### 暂时不做
|
||||
|
||||
```text
|
||||
复杂缓存策略
|
||||
Sorted Set 复习调度
|
||||
复杂分布式任务调度
|
||||
全量通知推送(APNs)
|
||||
复杂排行榜
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. RedisService 方法清单
|
||||
|
||||
```text
|
||||
get(key) — 读取
|
||||
set(key, value) — 写入
|
||||
del(key) — 删除
|
||||
exists(key) — 判断存在
|
||||
expire(key, ttl) — 设置过期
|
||||
ttl(key) — 查看剩余时间
|
||||
incr(key) — 自增(限流计数)
|
||||
setNx(key, value) — 不存在才写入(锁)
|
||||
lock(key, ttl) — 获取分布式锁,返回 token
|
||||
unlock(key, token) — 释放锁,校验 token,防止误删
|
||||
```
|
||||
|
||||
锁的实现注意:
|
||||
|
||||
- 锁必须设置 TTL
|
||||
- 解锁时必须校验 value/token,不能误删别人的锁
|
||||
- 锁的 value 用随机 token,解锁时比对
|
||||
|
||||
---
|
||||
|
||||
## 10. 一句话总结
|
||||
|
||||
> **Redis 在知习里不是"另一个 MySQL",它是系统的加速器和调度器。MySQL 存结果,Redis 管过程。**
|
||||
169
SECURITY.md
169
SECURITY.md
@ -1,169 +0,0 @@
|
||||
# 知习 api-server 安全基线
|
||||
|
||||
> v0.1 安全设计文档。本后端存储用户资料、知识库、上传文件、主动回忆回答、AI 分析结果和学习记录,第一版必须建立基础安全边界。
|
||||
|
||||
---
|
||||
|
||||
## 1. 全局安全中间件
|
||||
|
||||
| 措施 | 实现 | 文件 |
|
||||
|------|------|------|
|
||||
| helmet | `app.use(helmet())` 设置安全 HTTP 头 | `src/main.ts` |
|
||||
| CORS | 仅允许配置域名。生产环境仅允许 `longde.cloud` | `src/main.ts` |
|
||||
| body size limit | JSON 请求体最大 10MB | `src/main.ts` |
|
||||
| 异常过滤 | 生产环境不返回 stack trace | `src/common/filters/global-exception.filter.ts` |
|
||||
|
||||
---
|
||||
|
||||
## 2. 认证与 Token
|
||||
|
||||
### JWT
|
||||
|
||||
- `accessToken`: JWT,1 小时过期
|
||||
- `refreshToken`: 128 位随机 hex,入库只存 SHA-256 hash
|
||||
- logout 时 `revokedAt = now()` 撤销所有 refresh token
|
||||
- `/users/me` 及其所有子路由强制 `@UseGuards(JwtAuthGuard)`
|
||||
|
||||
```
|
||||
POST /auth/apple → 返回 accessToken + refreshToken
|
||||
POST /auth/refresh → 消耗旧 refreshToken,发放新 token pair(rotation)
|
||||
POST /auth/logout → 撤销该用户所有 refresh token
|
||||
```
|
||||
|
||||
### 存储安全
|
||||
|
||||
```
|
||||
refresh_tokens.tokenHash = SHA-256(实际 token)
|
||||
数据库中永远不存明文 refreshToken
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 权限与越权防护
|
||||
|
||||
### 资源归属校验
|
||||
|
||||
所有用户资源操作必须校验 `userId` 归属:
|
||||
|
||||
```ts
|
||||
// src/common/utils/security.util.ts
|
||||
export async function findByIdAndUserId(delegate, id, userId, resourceName)
|
||||
export function ensureOwnership(record, userId, resourceName)
|
||||
```
|
||||
|
||||
### 需校验的资源
|
||||
|
||||
| 资源 | 校验字段 |
|
||||
|------|---------|
|
||||
| KnowledgeBase | `userId` |
|
||||
| KnowledgeItem | `userId` |
|
||||
| LearningSession | `userId` |
|
||||
| ActiveRecallAnswer | `userId` |
|
||||
| AiAnalysisJob | `userId` |
|
||||
| AiAnalysisResult | `userId` |
|
||||
| FocusItem | `userId` |
|
||||
| ReviewCard | `userId` |
|
||||
| ReviewLog | `userId` |
|
||||
| DocumentImport | `userId` |
|
||||
|
||||
---
|
||||
|
||||
## 4. 参数校验
|
||||
|
||||
- 全局 `StrictValidationPipe`:
|
||||
- `whitelist: true` — 自动剥离未声明字段
|
||||
- `forbidNonWhitelisted: true` — 未知字段返回 400
|
||||
- 字符串字段最大长度 5000 字符
|
||||
- 分页 DTO: page≥1, limit 1-100
|
||||
|
||||
---
|
||||
|
||||
## 5. 限流(Redis)
|
||||
|
||||
| 场景 | Key | 限制 |
|
||||
|------|-----|------|
|
||||
| 登录 | `rate:ip:{ip}:login:{date}` | 20次/IP/天 |
|
||||
| 反馈 | `rate:ip:{ip}:feedback:hourly` | 5次/IP/时 |
|
||||
| AI 分析 | `rate:user:{userId}:ai:daily:{date}` | 50次/用户/天 |
|
||||
| 文件上传 | `rate:user:{userId}:upload:hourly` | 10次/用户/时 |
|
||||
|
||||
实现: `src/common/utils/rate-limit.service.ts`
|
||||
|
||||
---
|
||||
|
||||
## 6. 文件上传安全
|
||||
|
||||
| 措施 | 说明 |
|
||||
|------|------|
|
||||
| 类型白名单 | PDF, Word, Excel, 纯文本, Markdown, CSV, PNG, JPEG, WebP |
|
||||
| 大小限制 | 最大 20MB |
|
||||
| 随机文件名 | `sanitizeFilename()` 生成随机 key,不信任用户原始文件名 |
|
||||
| 默认私有 | 所有文件默认私有访问 |
|
||||
| 路径隔离 | `users/{userId}/...` |
|
||||
|
||||
---
|
||||
|
||||
## 7. Redis 安全使用
|
||||
|
||||
- 不存核心业务结果(用户资料/知识点/AI分析结果等必须在 MySQL)
|
||||
- 队列任务只存 `jobId`/`userId` 等引用 ID
|
||||
- 所有临时 key 必须设置 TTL
|
||||
- 防重复提交锁必须有 TTL,解锁校验 token
|
||||
- 不在 Redis 中存 token 明文
|
||||
|
||||
---
|
||||
|
||||
## 8. COS 安全使用
|
||||
|
||||
- Bucket 默认私有读写
|
||||
- 后端不向前端暴露 SecretId/SecretKey
|
||||
- 下载私有文件通过签名 URL
|
||||
- 上传路径按 `users/{userId}/{randomKey}` 组织
|
||||
- 预留临时上传 URL(STS)机制
|
||||
|
||||
---
|
||||
|
||||
## 9. Swagger 安全
|
||||
|
||||
- 开发环境默认开启
|
||||
- 生产环境默认关闭
|
||||
- 生产环境如需开启,必须配置 Basic Auth(`SWAGGER_USER`/`SWAGGER_PASSWORD`)
|
||||
- 生产环境手动设置 `ENABLE_SWAGGER=true`
|
||||
|
||||
---
|
||||
|
||||
## 10. 数据库安全
|
||||
|
||||
- 不使用 root 连接业务
|
||||
- 业务账号 `zhixi_user` 仅需 SELECT/INSERT/UPDATE/DELETE
|
||||
- 迁移账号和业务账号分离(`prisma db push` 与运行时连接帐号可不同)
|
||||
- 数据库自动备份建议: `mysqldump zhixi | gzip > backup-$(date +%Y%m%d).sql.gz`
|
||||
|
||||
### 日志中禁止打印
|
||||
|
||||
```
|
||||
DATABASE_URL(含密码)
|
||||
JWT_SECRET
|
||||
AI_API_KEY
|
||||
COS SecretKey
|
||||
用户完整 refreshToken
|
||||
用户上传文件的完整内容
|
||||
Authorization header
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 安全检查清单
|
||||
|
||||
- [x] helmet 已启用
|
||||
- [x] CORS 仅允许白名单域名
|
||||
- [x] JWT + refresh token rotation + hash 存储
|
||||
- [x] logout 撤销 refresh token
|
||||
- [x] 所有用户数据接口需要认证
|
||||
- [x] 资源所有权校验工具已就绪
|
||||
- [x] StrictValidationPipe 全局启用(whitelist + forbidNonWhitelisted)
|
||||
- [x] Redis 限流已实现
|
||||
- [x] 文件类型/大小白名单
|
||||
- [x] 全局异常过滤器生产环境不暴露 stack trace
|
||||
- [x] Swagger 生产环境默认关闭
|
||||
- [x] 敏感信息不在日志中打印原则已确立
|
||||
885
docs/AI回答.md
Normal file
885
docs/AI回答.md
Normal file
@ -0,0 +1,885 @@
|
||||
([Files][1])([Files][2])([Files][3])([Files][4])([Files][5])
|
||||
|
||||
可以。下面我把 **知习后端 Redis 设计** 单独整理一版。
|
||||
|
||||
你可以把它理解成:
|
||||
|
||||
```text
|
||||
MySQL:长期真实数据,必须可靠保存
|
||||
Redis:短期状态、缓存、队列、限流、锁、任务进度
|
||||
```
|
||||
|
||||
Redis **不需要建表**,需要设计的是:
|
||||
|
||||
```text
|
||||
1. Redis 用在哪些场景
|
||||
2. Key 怎么命名
|
||||
3. Value 存什么
|
||||
4. 过期时间多久
|
||||
5. 哪些数据绝对不能只放 Redis
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 一、Redis 在知习里的定位
|
||||
|
||||
Redis 不作为主数据库。
|
||||
|
||||
它主要负责:
|
||||
|
||||
```text
|
||||
1. 缓存
|
||||
2. 限流
|
||||
3. 队列
|
||||
4. 临时任务状态
|
||||
5. 分布式锁
|
||||
6. 防重复提交
|
||||
7. AI 调用次数统计
|
||||
8. 短期 token / 黑名单
|
||||
9. 通知任务调度
|
||||
```
|
||||
|
||||
核心业务数据仍然必须写入 MySQL:
|
||||
|
||||
```text
|
||||
用户
|
||||
知识库
|
||||
知识点
|
||||
学习记录
|
||||
主动回忆回答
|
||||
AI 分析结果
|
||||
待巩固项
|
||||
复习计划
|
||||
学习活跃记录
|
||||
通知记录
|
||||
用户设置
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 二、Redis Key 命名规范
|
||||
|
||||
建议统一用这种格式:
|
||||
|
||||
```text
|
||||
业务域:对象类型:对象ID:字段
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
cache:user:123:profile
|
||||
rate:user:123:ai:daily:2026-05-09
|
||||
lock:ai-analysis:session:987
|
||||
job:ai-analysis:abc123:status
|
||||
```
|
||||
|
||||
统一规则:
|
||||
|
||||
```text
|
||||
1. 全部小写
|
||||
2. 用冒号 : 分隔
|
||||
3. 从大范围到小范围
|
||||
4. userId、jobId、sessionId 明确写在 key 里
|
||||
5. 带日期的 key 用 YYYY-MM-DD
|
||||
6. 所有临时 key 必须设置 TTL
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 三、Redis 主要使用场景
|
||||
|
||||
## 1. 缓存 Cache
|
||||
|
||||
用于缓存高频读取的数据,减少 MySQL 压力。
|
||||
|
||||
### 用户资料缓存
|
||||
|
||||
```text
|
||||
key:
|
||||
cache:user:{userId}:profile
|
||||
|
||||
value:
|
||||
{
|
||||
"id": 123,
|
||||
"nickname": "李明",
|
||||
"avatarUrl": null,
|
||||
"learningIdentity": "系统学习者",
|
||||
"learningDirection": "认知科学"
|
||||
}
|
||||
|
||||
ttl:
|
||||
5-10 分钟
|
||||
```
|
||||
|
||||
### 用户知识库列表缓存
|
||||
|
||||
```text
|
||||
key:
|
||||
cache:user:{userId}:knowledge-bases
|
||||
|
||||
value:
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"title": "认知心理学",
|
||||
"itemCount": 42
|
||||
}
|
||||
]
|
||||
|
||||
ttl:
|
||||
3-5 分钟
|
||||
```
|
||||
|
||||
### 当前用户设置缓存
|
||||
|
||||
```text
|
||||
key:
|
||||
cache:user:{userId}:preferences
|
||||
|
||||
ttl:
|
||||
10 分钟
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
```text
|
||||
缓存可以丢
|
||||
MySQL 不能丢
|
||||
缓存更新不及时也没关系,但关键业务查询必须以 MySQL 为准
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 限流 Rate Limit
|
||||
|
||||
用于控制请求频率和 AI 成本。
|
||||
|
||||
### 用户每日 AI 调用次数
|
||||
|
||||
```text
|
||||
key:
|
||||
rate:user:{userId}:ai:daily:{date}
|
||||
|
||||
example:
|
||||
rate:user:123:ai:daily:2026-05-09
|
||||
|
||||
value:
|
||||
8
|
||||
|
||||
ttl:
|
||||
到当天结束,或者 24 小时
|
||||
```
|
||||
|
||||
用途:
|
||||
|
||||
```text
|
||||
限制每天 AI 分析次数
|
||||
限制生成回忆测试次数
|
||||
限制找薄弱知识点次数
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### IP 请求频率限制
|
||||
|
||||
```text
|
||||
key:
|
||||
rate:ip:{ip}:request:{minute}
|
||||
|
||||
example:
|
||||
rate:ip:1.2.3.4:request:2026-05-09T10:35
|
||||
|
||||
value:
|
||||
42
|
||||
|
||||
ttl:
|
||||
60-120 秒
|
||||
```
|
||||
|
||||
用途:
|
||||
|
||||
```text
|
||||
防刷接口
|
||||
防反馈表单乱提交
|
||||
防登录接口暴力请求
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 登录尝试次数
|
||||
|
||||
```text
|
||||
key:
|
||||
rate:login:{ip}:{date}
|
||||
|
||||
ttl:
|
||||
10-30 分钟
|
||||
```
|
||||
|
||||
Apple 登录一般问题不大,但后面如果有邮箱登录、验证码登录,这个会用到。
|
||||
|
||||
---
|
||||
|
||||
## 3. 分布式锁 Lock
|
||||
|
||||
用于防止重复提交。
|
||||
|
||||
### 防止重复 AI 分析
|
||||
|
||||
```text
|
||||
key:
|
||||
lock:ai-analysis:session:{sessionId}
|
||||
|
||||
example:
|
||||
lock:ai-analysis:session:987
|
||||
|
||||
value:
|
||||
randomToken
|
||||
|
||||
ttl:
|
||||
60-300 秒
|
||||
```
|
||||
|
||||
场景:
|
||||
|
||||
```text
|
||||
用户连续点两次“提交 AI 分析”
|
||||
后端只允许创建一个分析任务
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 防止重复导入资料
|
||||
|
||||
```text
|
||||
key:
|
||||
lock:document-import:{importId}
|
||||
|
||||
ttl:
|
||||
5-30 分钟
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 防止重复生成复习计划
|
||||
|
||||
```text
|
||||
key:
|
||||
lock:review-plan:user:{userId}:item:{itemId}
|
||||
|
||||
ttl:
|
||||
60-300 秒
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
```text
|
||||
锁一定要设置 TTL
|
||||
解锁时要校验 value,不能误删别人的锁
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. AI 分析任务状态
|
||||
|
||||
AI 分析建议用异步任务。
|
||||
|
||||
流程:
|
||||
|
||||
```text
|
||||
App 提交回答
|
||||
→ 后端创建 ai_analysis_jobs 记录
|
||||
→ 加入 Redis 队列
|
||||
→ 返回 jobId
|
||||
→ Worker 调用 AI
|
||||
→ 结果写入 MySQL
|
||||
→ Redis 状态改为 completed
|
||||
```
|
||||
|
||||
### 任务状态 key
|
||||
|
||||
```text
|
||||
key:
|
||||
job:ai-analysis:{jobId}:status
|
||||
|
||||
value:
|
||||
pending / processing / completed / failed
|
||||
|
||||
ttl:
|
||||
24 小时
|
||||
```
|
||||
|
||||
### 任务进度 key
|
||||
|
||||
```text
|
||||
key:
|
||||
job:ai-analysis:{jobId}:progress
|
||||
|
||||
value:
|
||||
0-100
|
||||
|
||||
ttl:
|
||||
24 小时
|
||||
```
|
||||
|
||||
### 任务错误信息
|
||||
|
||||
```text
|
||||
key:
|
||||
job:ai-analysis:{jobId}:error
|
||||
|
||||
value:
|
||||
"AI provider timeout"
|
||||
|
||||
ttl:
|
||||
24 小时
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
```text
|
||||
Redis 只存临时状态
|
||||
最终任务记录和分析结果必须写入 MySQL:
|
||||
ai_analysis_jobs
|
||||
ai_analysis_results
|
||||
focus_items
|
||||
review_cards
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 资料导入任务状态
|
||||
|
||||
导入资料也建议异步。
|
||||
|
||||
场景:
|
||||
|
||||
```text
|
||||
上传 PDF
|
||||
粘贴长文本
|
||||
导入链接
|
||||
AI 解析生成知识点
|
||||
```
|
||||
|
||||
### 导入任务状态
|
||||
|
||||
```text
|
||||
key:
|
||||
job:document-import:{importId}:status
|
||||
|
||||
value:
|
||||
pending / parsing / chunking / generating / completed / failed
|
||||
|
||||
ttl:
|
||||
24 小时
|
||||
```
|
||||
|
||||
### 导入进度
|
||||
|
||||
```text
|
||||
key:
|
||||
job:document-import:{importId}:progress
|
||||
|
||||
value:
|
||||
0-100
|
||||
|
||||
ttl:
|
||||
24 小时
|
||||
```
|
||||
|
||||
### 导入处理中提示
|
||||
|
||||
```text
|
||||
key:
|
||||
job:document-import:{importId}:message
|
||||
|
||||
value:
|
||||
"正在提取关键知识点"
|
||||
|
||||
ttl:
|
||||
24 小时
|
||||
```
|
||||
|
||||
最终结果写入 MySQL:
|
||||
|
||||
```text
|
||||
document_imports
|
||||
uploaded_files
|
||||
knowledge_items
|
||||
knowledge_item_relations
|
||||
tags
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. BullMQ 队列
|
||||
|
||||
如果后端是 Node.js / NestJS,建议用 BullMQ。
|
||||
|
||||
队列由 BullMQ 自动管理 Redis key,不需要你自己建。
|
||||
|
||||
建议预留 3 个队列:
|
||||
|
||||
```text
|
||||
ai-analysis
|
||||
document-import
|
||||
notification
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ai-analysis 队列
|
||||
|
||||
任务数据:
|
||||
|
||||
```json
|
||||
{
|
||||
"jobId": 123,
|
||||
"userId": 456,
|
||||
"sessionId": 789,
|
||||
"answerId": 1001,
|
||||
"jobType": "active_recall_analysis"
|
||||
}
|
||||
```
|
||||
|
||||
处理逻辑:
|
||||
|
||||
```text
|
||||
读取用户回答
|
||||
调用 AI
|
||||
生成分析结果
|
||||
写入 ai_analysis_results
|
||||
生成 focus_items
|
||||
生成 review_cards
|
||||
发送通知
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### document-import 队列
|
||||
|
||||
任务数据:
|
||||
|
||||
```json
|
||||
{
|
||||
"importId": 123,
|
||||
"userId": 456,
|
||||
"knowledgeBaseId": 789,
|
||||
"sourceType": "file"
|
||||
}
|
||||
```
|
||||
|
||||
处理逻辑:
|
||||
|
||||
```text
|
||||
解析文件
|
||||
提取文本
|
||||
分段
|
||||
生成知识点
|
||||
写入 knowledge_items
|
||||
更新 document_imports 状态
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### notification 队列
|
||||
|
||||
任务数据:
|
||||
|
||||
```json
|
||||
{
|
||||
"userId": 456,
|
||||
"type": "review_due",
|
||||
"title": "8 张卡片今日到期复习",
|
||||
"data": {
|
||||
"reviewCount": 8
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
处理逻辑:
|
||||
|
||||
```text
|
||||
写入 notifications 表
|
||||
后面可扩展推送 APNs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 四、Redis Key 总表
|
||||
|
||||
## 缓存类
|
||||
|
||||
```text
|
||||
cache:user:{userId}:profile
|
||||
cache:user:{userId}:preferences
|
||||
cache:user:{userId}:knowledge-bases
|
||||
cache:knowledge-base:{knowledgeBaseId}:summary
|
||||
cache:review:user:{userId}:due-count
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 限流类
|
||||
|
||||
```text
|
||||
rate:user:{userId}:ai:daily:{date}
|
||||
rate:user:{userId}:feedback:hourly
|
||||
rate:ip:{ip}:request:{minute}
|
||||
rate:ip:{ip}:login:{date}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 锁类
|
||||
|
||||
```text
|
||||
lock:ai-analysis:session:{sessionId}
|
||||
lock:ai-analysis:answer:{answerId}
|
||||
lock:document-import:{importId}
|
||||
lock:review-plan:user:{userId}:item:{itemId}
|
||||
lock:feedback:ip:{ip}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 任务状态类
|
||||
|
||||
```text
|
||||
job:ai-analysis:{jobId}:status
|
||||
job:ai-analysis:{jobId}:progress
|
||||
job:ai-analysis:{jobId}:error
|
||||
|
||||
job:document-import:{importId}:status
|
||||
job:document-import:{importId}:progress
|
||||
job:document-import:{importId}:message
|
||||
job:document-import:{importId}:error
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 会话临时状态
|
||||
|
||||
```text
|
||||
session:learning:{sessionId}:heartbeat
|
||||
session:learning:{sessionId}:current-step
|
||||
session:active-recall:{sessionId}:draft
|
||||
```
|
||||
|
||||
例如用户正在写回答,可以短期保存草稿:
|
||||
|
||||
```text
|
||||
key:
|
||||
session:active-recall:{sessionId}:draft
|
||||
|
||||
ttl:
|
||||
1-24 小时
|
||||
```
|
||||
|
||||
最终提交后还是写 MySQL。
|
||||
|
||||
---
|
||||
|
||||
## Token / 黑名单
|
||||
|
||||
```text
|
||||
auth:refresh-token:blacklist:{tokenId}
|
||||
auth:access-token:blacklist:{jwtId}
|
||||
```
|
||||
|
||||
退出登录或注销账号时可用。
|
||||
|
||||
---
|
||||
|
||||
# 五、TTL 建议
|
||||
|
||||
```text
|
||||
用户资料缓存:5-10 分钟
|
||||
知识库列表缓存:3-5 分钟
|
||||
AI 每日限流:到当天结束或 24 小时
|
||||
IP 请求限流:60-120 秒
|
||||
登录尝试限流:10-30 分钟
|
||||
AI 分析任务状态:24 小时
|
||||
资料导入任务状态:24 小时
|
||||
分布式锁:60 秒到 30 分钟,按任务类型决定
|
||||
学习草稿:1-24 小时
|
||||
Token 黑名单:到 token 原本过期时间
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 六、Redis 数据类型建议
|
||||
|
||||
## String
|
||||
|
||||
最常用。
|
||||
|
||||
用于:
|
||||
|
||||
```text
|
||||
缓存 JSON
|
||||
计数器
|
||||
状态
|
||||
锁
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
rate:user:123:ai:daily:2026-05-09 = 8
|
||||
job:ai-analysis:1001:status = processing
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hash
|
||||
|
||||
可选,用于对象字段更新频繁的场景。
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
job:ai-analysis:1001
|
||||
status = processing
|
||||
progress = 40
|
||||
message = 正在分析薄弱点
|
||||
```
|
||||
|
||||
v0.1 也可以先用 String 多 key,简单直接。
|
||||
|
||||
---
|
||||
|
||||
## List / Stream
|
||||
|
||||
队列相关,但如果使用 BullMQ,不需要自己操作。
|
||||
|
||||
---
|
||||
|
||||
## Set
|
||||
|
||||
可选。
|
||||
|
||||
比如记录某天处理过的学习项:
|
||||
|
||||
```text
|
||||
set:user:{userId}:reviewed-items:{date}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sorted Set
|
||||
|
||||
后期可用于按时间排序的任务。
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
zset:review:due
|
||||
```
|
||||
|
||||
但 v0.1 可以先不做,复习到期直接查 MySQL。
|
||||
|
||||
---
|
||||
|
||||
# 七、哪些不要放 Redis
|
||||
|
||||
不要把这些只放 Redis:
|
||||
|
||||
```text
|
||||
用户资料
|
||||
知识库内容
|
||||
知识点内容
|
||||
学习记录
|
||||
主动回忆回答
|
||||
AI 分析结果
|
||||
待巩固项
|
||||
复习卡片
|
||||
复习记录
|
||||
学习活跃记录
|
||||
通知记录
|
||||
用户设置
|
||||
协议同意记录
|
||||
```
|
||||
|
||||
这些全部要写 MySQL。
|
||||
|
||||
Redis 可以缓存它们,但不是唯一来源。
|
||||
|
||||
---
|
||||
|
||||
# 八、Redis 和 MySQL 的典型组合流程
|
||||
|
||||
## AI 分析流程
|
||||
|
||||
```text
|
||||
1. MySQL 创建 ai_analysis_jobs
|
||||
2. Redis 加入 ai-analysis 队列
|
||||
3. Redis 存 job 状态 processing
|
||||
4. Worker 调用 AI
|
||||
5. MySQL 写 ai_analysis_results
|
||||
6. MySQL 写 focus_items
|
||||
7. MySQL 写 review_cards
|
||||
8. Redis 存 job 状态 completed
|
||||
9. MySQL 写 notifications
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 资料导入流程
|
||||
|
||||
```text
|
||||
1. MySQL 创建 document_imports
|
||||
2. Redis 加入 document-import 队列
|
||||
3. Redis 存导入进度
|
||||
4. Worker 解析文件
|
||||
5. MySQL 写 knowledge_items
|
||||
6. MySQL 更新 document_imports 为 success
|
||||
7. Redis 状态 completed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 学习活跃图流程
|
||||
|
||||
```text
|
||||
1. 用户完成学习动作
|
||||
2. MySQL 写 learning_records
|
||||
3. MySQL 更新 daily_learning_activities
|
||||
4. Redis 可短期缓存今日活跃统计
|
||||
5. App 查询活跃图时优先查 MySQL,必要时加缓存
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 九、v0.1 Redis 最小落地范围
|
||||
|
||||
第一版不用把所有 Redis 场景都做完。
|
||||
|
||||
建议先做:
|
||||
|
||||
```text
|
||||
1. Redis 连接
|
||||
2. /health 检查 Redis
|
||||
3. RedisService
|
||||
4. AI 每日调用限流
|
||||
5. AI 分析队列
|
||||
6. AI 分析任务状态
|
||||
7. 防重复提交锁
|
||||
8. document-import 队列预留
|
||||
9. notification 队列预留
|
||||
```
|
||||
|
||||
暂时不做:
|
||||
|
||||
```text
|
||||
复杂缓存策略
|
||||
Sorted Set 复习调度
|
||||
复杂分布式任务调度
|
||||
全量通知推送
|
||||
复杂排行榜
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 十、给 Trae 的提示词
|
||||
|
||||
```text
|
||||
请为「知习」api-server 设计并接入 Redis。
|
||||
|
||||
注意:
|
||||
Redis 不需要像 MySQL 一样建表。
|
||||
Redis 只用于缓存、限流、队列、临时状态、分布式锁、防重复提交和任务进度。
|
||||
核心业务数据必须写入 MySQL,不能只存在 Redis。
|
||||
|
||||
请完成以下内容:
|
||||
|
||||
1. 基础接入
|
||||
- docker-compose 增加 redis:7-alpine
|
||||
- 增加 RedisModule
|
||||
- 增加 RedisService
|
||||
- 支持 REDIS_HOST、REDIS_PORT、REDIS_PASSWORD、REDIS_DB、REDIS_URL
|
||||
- /health 检查 Redis 是否可用
|
||||
|
||||
2. RedisService 方法
|
||||
- get
|
||||
- set
|
||||
- del
|
||||
- exists
|
||||
- expire
|
||||
- ttl
|
||||
- incr
|
||||
- setNx
|
||||
- lock
|
||||
- unlock
|
||||
|
||||
3. Key 命名规范
|
||||
请创建文档 docs/redis-key-design.md,包含以下 key 规范:
|
||||
|
||||
缓存:
|
||||
cache:user:{userId}:profile
|
||||
cache:user:{userId}:preferences
|
||||
cache:user:{userId}:knowledge-bases
|
||||
|
||||
限流:
|
||||
rate:user:{userId}:ai:daily:{date}
|
||||
rate:ip:{ip}:request:{minute}
|
||||
rate:user:{userId}:feedback:hourly
|
||||
|
||||
锁:
|
||||
lock:ai-analysis:session:{sessionId}
|
||||
lock:ai-analysis:answer:{answerId}
|
||||
lock:document-import:{importId}
|
||||
lock:review-plan:user:{userId}:item:{itemId}
|
||||
|
||||
任务状态:
|
||||
job:ai-analysis:{jobId}:status
|
||||
job:ai-analysis:{jobId}:progress
|
||||
job:ai-analysis:{jobId}:error
|
||||
job:document-import:{importId}:status
|
||||
job:document-import:{importId}:progress
|
||||
job:document-import:{importId}:message
|
||||
job:document-import:{importId}:error
|
||||
|
||||
4. BullMQ 队列
|
||||
请预留以下队列:
|
||||
- ai-analysis
|
||||
- document-import
|
||||
- notification
|
||||
|
||||
5. AI 分析任务
|
||||
请实现基础队列结构:
|
||||
- 创建 AI 分析任务时写入 MySQL ai_analysis_jobs
|
||||
- 添加任务到 Redis BullMQ 队列
|
||||
- Redis 记录任务 status/progress
|
||||
- Worker 处理完成后更新 MySQL
|
||||
- Redis 更新状态为 completed
|
||||
|
||||
6. 限流
|
||||
请实现基础 AI 调用限流:
|
||||
rate:user:{userId}:ai:daily:{date}
|
||||
用于限制用户每日 AI 分析调用次数。
|
||||
|
||||
7. 分布式锁
|
||||
请实现 lock/unlock 工具,防止重复提交 AI 分析任务。
|
||||
锁必须有 TTL。
|
||||
解锁时要校验 token,不能误删其他请求的锁。
|
||||
|
||||
8. 注意事项
|
||||
- 不要把用户、知识库、学习记录、AI 分析结果、待巩固项、复习计划只存 Redis
|
||||
- Redis 中所有临时状态必须设置 TTL
|
||||
- BullMQ 自动创建的 Redis key 不需要手动管理
|
||||
- 代码要模块化,方便后续扩展
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
一句话总结:
|
||||
|
||||
**Redis 在知习里不是“另一个 MySQL”,它是系统的加速器和调度器。MySQL 存结果,Redis 管过程。**
|
||||
|
||||
[1]: file://my_files/file_00000000e760722fbb391fe031a23b24 "personal_developer_startup_plan.md"
|
||||
[2]: file://my_files/file_00000000cbe0722fb8f20caa41630738 "Pasted text.txt"
|
||||
[3]: file://my_files/file_0000000013c071fdbc2b510f32da8546 "Pasted text.txt"
|
||||
[4]: file://my_files/file_00000000ffd071fd9492b93fd9ebf5ba "Pasted text.txt"
|
||||
[5]: file://my_files/file_0000000061e471f590475885fd76860c "REAL_MIGRATION_STATUS.md"
|
||||
Loading…
x
Reference in New Issue
Block a user