query-database/docs/TECH-MySQL查询练习网站-技术架构.md
2026-03-25 15:46:20 +08:00

245 lines
5.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 1.Architecture design
```mermaid
graph TD
U["User Browser"] --> F["Vue Frontend Application"]
F --> S["Backend API Service"]
S --> M["MySQL 8 Database"]
S --> P["SQLite (Metadata)"]
subgraph "Frontend Layer"
F
end
subgraph "Backend Layer"
S
end
subgraph "Data Layer"
M
end
subgraph "Service Layer (Provided by Supabase)"
P
end
```
## 2.Technology Description
- Frontend: Vue3 + Vite + TailwindCSS
- Backend: Go + Gin
- Auth: JWT后端签发与校验
- Metadata: SQLite用户、题目、进度、用户数据库列表等
- SQL Execution Engine: MySQL 8用于模拟库与用户导入库的执行环境
## 3.Route definitions
| Route | Purpose |
|-------|---------|
| /login | 登录/注册页 |
| / | 首页:题目分级列表、新手引导、继续练习 |
| /practice/:id | 练习页SQL 编辑、运行、结果与校验 |
| /databases | 数据库管理:选择模拟库、导入自定义库、激活当前库 |
## 4.API definitions (If it includes backend services)
### 4.1 Core Types (TypeScript)
```ts
export type Level = 'beginner' | 'normal' | 'advanced'
export type ModuleKey = 'shop' | 'hr'
export type ActiveDatabase = {
id: string
name: string
source: 'mock' | 'imported'
schemaName: string
}
export type ExerciseSummary = {
id: string
title: string
level: Level
isSolved: boolean
}
export type ExecuteSqlRequest = {
exerciseId: string
sql: string
}
export type ExecuteSqlResponse = {
ok: boolean
durationMs: number
columns?: string[]
rows?: Array<Record<string, unknown>>
errorMessage?: string
verdict?: 'pass' | 'fail'
hint?: string
}
export type ImportDatabaseRequest = {
name: string
initSqlFileUrl: string
}
export type UserDatabase = {
id: string
name: string
source: 'mock' | 'imported'
createdAt: string
}
```
### 4.2 Core API
- 获取题目列表
```
GET /api/exercises?level=beginner|normal|advanced&query=...
```
- 获取题目详情(含描述与校验配置)
```
GET /api/exercises/:id
```
- 执行 SQL + 返回结果 + 判题
```
POST /api/sql/execute
```
Request: ExecuteSqlRequest
- 保存/更新进度(草稿 SQL、是否通过
```
POST /api/progress/upsert
```
- 获取/切换当前激活数据库
```
GET /api/user-databases
POST /api/user-databases/activate
```
- 导入自定义数据库(先上传文件到 Storage再触发导入
```
POST /api/user-databases/import
```
Request: ImportDatabaseRequest
- 新手引导状态(是否已完成/已跳过)
```
GET /api/onboarding
POST /api/onboarding/complete
```
## 5.Server architecture diagram (If it includes backend services)
```mermaid
graph TD
A["Client / Frontend"] --> B["API Controller"]
B --> C["Practice Service (Execute + Judge)"]
B --> D["Exercise Service"]
B --> E["Database Import Service"]
C --> F["MySQL Repository"]
D --> G["SQLite Repository (Metadata)"]
E --> F
subgraph "Server"
B
C
D
E
F
G
end
```
## 6.Data model(if applicable)
### 6.1 Data model definition
SQLite 用于题目/进度/用户库元数据MySQL 用于实际运行 SQL 的数据面。)
```mermaid
erDiagram
PROFILE {
uuid id
text email
timestamptz created_at
}
EXERCISE {
uuid id
text title
text level
text prompt
text answer_sql
}
USER_PROGRESS {
uuid id
uuid user_id
uuid exercise_id
text draft_sql
bool is_solved
timestamptz updated_at
}
USER_DATABASE {
uuid id
uuid user_id
text name
text source
text mysql_schema_name
bool is_active
timestamptz created_at
}
```
### 6.2 Data Definition Language
Profile Table (profiles)
```
CREATE TABLE profiles (
id UUID PRIMARY KEY,
email TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
GRANT SELECT ON profiles TO anon;
GRANT ALL PRIVILEGES ON profiles TO authenticated;
```
Exercise Table (exercises)
```
CREATE TABLE exercises (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
level TEXT NOT NULL CHECK (level IN ('beginner','normal','advanced')),
prompt TEXT NOT NULL,
answer_sql TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
GRANT SELECT ON exercises TO anon;
GRANT ALL PRIVILEGES ON exercises TO authenticated;
```
User Progress Table (user_progress)
```
CREATE TABLE user_progress (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
exercise_id UUID NOT NULL,
draft_sql TEXT,
is_solved BOOLEAN DEFAULT FALSE,
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_user_progress_user_id ON user_progress(user_id);
CREATE INDEX idx_user_progress_exercise_id ON user_progress(exercise_id);
GRANT SELECT ON user_progress TO anon;
GRANT ALL PRIVILEGES ON user_progress TO authenticated;
```
User Database Table (user_databases)
```
CREATE TABLE user_databases (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
name TEXT NOT NULL,
source TEXT NOT NULL CHECK (source IN ('mock','imported')),
mysql_schema_name TEXT NOT NULL,
is_active BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_user_databases_user_id ON user_databases(user_id);
GRANT SELECT ON user_databases TO anon
```