docs: add initial architecture and schema draft
这个提交包含在:
174
docs/平台总体设计.md
普通文件
174
docs/平台总体设计.md
普通文件
@@ -0,0 +1,174 @@
|
|||||||
|
# 平台总体设计(草案)
|
||||||
|
|
||||||
|
> 目标:面向初学者的 OI/CSP 学习知识库 + 日常练习 + 模拟竞赛系统,并提供在线 C++ 编写/编译/调试能力。前后端分离:Next.js + C++(Drogon) + SQLite。
|
||||||
|
|
||||||
|
## 1. 术语与核心对象
|
||||||
|
|
||||||
|
- **用户(User)**:注册/登录;拥有积分、等级、学习进度。
|
||||||
|
- **题目(Problem)**:题面、标签、难度、来源(如 CSP/NOIP/自建)。
|
||||||
|
- **提交(Submission)**:用户对题目的一次代码提交(含编译/运行结果、耗时、内存、得分)。
|
||||||
|
- **练习(Practice)**:非比赛场景的做题记录(可以直接通过 submissions 体现)。
|
||||||
|
- **错题本(WrongBook)**:用户在练习/比赛中未通过的题目集合 + 错因备注。
|
||||||
|
- **比赛(Contest)**:模拟 CSP/NOIP 的比赛;包含题目列表、开始/结束、计分规则。
|
||||||
|
- **排名(Leaderboard)**:全站积分排行、比赛排行。
|
||||||
|
- **知识库(KnowledgeBase)**:学习文章/笔记/专题目录;可关联题目。
|
||||||
|
|
||||||
|
## 2. 技术架构
|
||||||
|
|
||||||
|
### 2.1 前端
|
||||||
|
|
||||||
|
- Next.js(App Router) + TypeScript + Tailwind
|
||||||
|
- 负责:题库/题面、编辑器页面、提交列表、错题本、排行、比赛大厅、知识库阅读
|
||||||
|
|
||||||
|
### 2.2 后端
|
||||||
|
|
||||||
|
- Drogon (HTTP + JSON)
|
||||||
|
- SQLite(单文件数据库,便于部署)
|
||||||
|
- 模块分层(建议):
|
||||||
|
- `controller/`:HTTP 路由
|
||||||
|
- `service/`:业务逻辑
|
||||||
|
- `repo/`:DB 访问(SQL + 映射)
|
||||||
|
- `domain/`:实体与枚举
|
||||||
|
- `judge/`:编译与判题执行器(后续)
|
||||||
|
|
||||||
|
### 2.3 在线编译/运行(安全边界)
|
||||||
|
|
||||||
|
- MVP:后端在临时目录中调用 `g++` 编译,并用子进程运行,使用 `ulimit`/超时 kill 做基础限制。
|
||||||
|
- 生产建议:判题/运行必须放在容器或隔离工具(如 nsjail/isolate)中;否则存在逃逸风险。
|
||||||
|
|
||||||
|
## 3. 数据库设计(SQLite)
|
||||||
|
|
||||||
|
### 3.1 表清单
|
||||||
|
|
||||||
|
1) `users`
|
||||||
|
- `id` INTEGER PK
|
||||||
|
- `username` TEXT UNIQUE
|
||||||
|
- `password_hash` TEXT
|
||||||
|
- `created_at` INTEGER
|
||||||
|
- `rating` INTEGER DEFAULT 0 (综合积分)
|
||||||
|
|
||||||
|
2) `problems`
|
||||||
|
- `id` INTEGER PK
|
||||||
|
- `slug` TEXT UNIQUE
|
||||||
|
- `title` TEXT
|
||||||
|
- `statement_md` TEXT
|
||||||
|
- `difficulty` INTEGER
|
||||||
|
- `source` TEXT
|
||||||
|
- `created_at` INTEGER
|
||||||
|
|
||||||
|
3) `problem_tags`
|
||||||
|
- `problem_id` INTEGER
|
||||||
|
- `tag` TEXT
|
||||||
|
- PK(`problem_id`,`tag`)
|
||||||
|
|
||||||
|
4) `submissions`
|
||||||
|
- `id` INTEGER PK
|
||||||
|
- `user_id` INTEGER
|
||||||
|
- `problem_id` INTEGER
|
||||||
|
- `language` TEXT (先支持 cpp)
|
||||||
|
- `code` TEXT
|
||||||
|
- `status` TEXT (Pending/Compiling/Running/AC/WA/TLE/MLE/RE/CE)
|
||||||
|
- `score` INTEGER
|
||||||
|
- `time_ms` INTEGER
|
||||||
|
- `memory_kb` INTEGER
|
||||||
|
- `created_at` INTEGER
|
||||||
|
|
||||||
|
5) `wrong_book`
|
||||||
|
- `user_id` INTEGER
|
||||||
|
- `problem_id` INTEGER
|
||||||
|
- `last_submission_id` INTEGER
|
||||||
|
- `note` TEXT
|
||||||
|
- `updated_at` INTEGER
|
||||||
|
- PK(`user_id`,`problem_id`)
|
||||||
|
|
||||||
|
6) `contests`
|
||||||
|
- `id` INTEGER PK
|
||||||
|
- `title` TEXT
|
||||||
|
- `starts_at` INTEGER
|
||||||
|
- `ends_at` INTEGER
|
||||||
|
- `rule_json` TEXT (计分规则/罚时规则)
|
||||||
|
|
||||||
|
7) `contest_problems`
|
||||||
|
- `contest_id` INTEGER
|
||||||
|
- `problem_id` INTEGER
|
||||||
|
- `idx` INTEGER
|
||||||
|
- PK(`contest_id`,`problem_id`)
|
||||||
|
|
||||||
|
8) `contest_registrations`
|
||||||
|
- `contest_id` INTEGER
|
||||||
|
- `user_id` INTEGER
|
||||||
|
- `registered_at` INTEGER
|
||||||
|
- PK(`contest_id`,`user_id`)
|
||||||
|
|
||||||
|
9) `kb_articles`
|
||||||
|
- `id` INTEGER PK
|
||||||
|
- `slug` TEXT UNIQUE
|
||||||
|
- `title` TEXT
|
||||||
|
- `content_md` TEXT
|
||||||
|
- `created_at` INTEGER
|
||||||
|
|
||||||
|
10) `kb_article_links`
|
||||||
|
- `article_id` INTEGER
|
||||||
|
- `problem_id` INTEGER
|
||||||
|
- PK(`article_id`,`problem_id`)
|
||||||
|
|
||||||
|
### 3.2 积分/排行
|
||||||
|
|
||||||
|
- 全站排行:按 `users.rating` 降序。
|
||||||
|
- rating 更新策略(MVP):
|
||||||
|
- 练习 AC:+difficulty * 常数
|
||||||
|
- 比赛:按名次发放奖励分(rule_json 可配置)
|
||||||
|
|
||||||
|
> 该策略后续可替换为 ELO/Codeforces 风格。
|
||||||
|
|
||||||
|
## 4. HTTP API 设计(v1草案)
|
||||||
|
|
||||||
|
统一前缀:`/api/v1`
|
||||||
|
|
||||||
|
### 4.1 Auth
|
||||||
|
- `POST /auth/register` {username,password}
|
||||||
|
- `POST /auth/login` {username,password} -> {token}
|
||||||
|
- 鉴权:`Authorization: Bearer <token>`(MVP 可用 HMAC JWT)
|
||||||
|
|
||||||
|
### 4.2 Problems
|
||||||
|
- `GET /problems?tag=&difficulty=&q=&page=`
|
||||||
|
- `GET /problems/:id`
|
||||||
|
|
||||||
|
### 4.3 Submissions
|
||||||
|
- `POST /problems/:id/submit` {language,code}
|
||||||
|
- `GET /submissions?user_id=&problem_id=&page=`
|
||||||
|
- `GET /submissions/:id`
|
||||||
|
|
||||||
|
### 4.4 WrongBook
|
||||||
|
- `GET /me/wrong-book`
|
||||||
|
- `PATCH /me/wrong-book/:problemId` {note}
|
||||||
|
- `DELETE /me/wrong-book/:problemId`
|
||||||
|
|
||||||
|
### 4.5 Contests
|
||||||
|
- `GET /contests`
|
||||||
|
- `GET /contests/:id`
|
||||||
|
- `POST /contests/:id/register`
|
||||||
|
- `GET /contests/:id/leaderboard`
|
||||||
|
|
||||||
|
### 4.6 Leaderboard
|
||||||
|
- `GET /leaderboard/global`
|
||||||
|
|
||||||
|
### 4.7 Knowledge Base
|
||||||
|
- `GET /kb/articles`
|
||||||
|
- `GET /kb/articles/:slug`
|
||||||
|
|
||||||
|
## 5. 测试策略(TDD)
|
||||||
|
|
||||||
|
- `repo` 层:用内存 SQLite(`:memory:`)+ 迁移脚本,做 CRUD 单测。
|
||||||
|
- `service` 层:对积分、错题本更新等写业务单测。
|
||||||
|
- `controller` 层:Drogon 自带测试/或以 HTTP 集成测试(启动测试服务器,发请求断言 JSON)。
|
||||||
|
|
||||||
|
## 6. 下一步落地顺序(MVP)
|
||||||
|
|
||||||
|
1) 用户注册/登录(token)
|
||||||
|
2) 题库(只读)+ 提交记录入库
|
||||||
|
3) 在线编译(仅编译 + 返回CE/OK),再扩展到运行
|
||||||
|
4) 错题本(由 WA/未通过自动写入)
|
||||||
|
5) 积分与全站排行
|
||||||
|
6) 比赛(创建/报名/排行榜)
|
||||||
|
7) 知识库文章与题目关联
|
||||||
在新工单中引用
屏蔽一个用户