docs: 建立 devdocs 开发文档集(13 份模块文档)
This commit is contained in:
1 parent
3e9592b006
commit
3b3496559b
15 files changed
+1685
-2
No files matched your search
@@ -0,0 +1,248 @@
|
||||
# 04 · 数据模型
|
||||
|
||||
> 所属:运动会积分榜系统 · 开发文档集
|
||||
> 版本:v0.1(讨论稿) · 2026-09-09
|
||||
> 上游:[README](./README.md) · 相关:[02-积分与排名规则](./02-积分与排名规则.md)、[05-接口与实时协议](./05-接口与实时协议.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 实体关系概览
|
||||
|
||||
```
|
||||
settings(赛事配置)
|
||||
|
||||
teams(单位) ──┬── athletes(运动员) ──┐
|
||||
│ ├── entries(报名项) ── results(成绩)
|
||||
sports(大项) ── events(小项) ────────┘ │
|
||||
│ ├── record_breaks(破纪录)
|
||||
└── scoring_profiles(积分模板)┘
|
||||
│
|
||||
score_ledger(积分流水) ── 汇总 ──▶ standings(排名视图/缓存)
|
||||
point_adjustments(人工调整) ──────────┘
|
||||
|
||||
users / sessions / audit_logs / change_log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 表结构
|
||||
|
||||
> SQLite 是动态类型,字段类型按习惯书写,真正的约束靠 `CHECK`、`UNIQUE`、外键与索引保证。
|
||||
|
||||
### settings — 赛事配置
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| key | TEXT PK | 如 `event.name`、`display.rotate_seconds` |
|
||||
| value | TEXT | JSON 或纯文本 |
|
||||
| updated_at | TEXT | ISO8601 |
|
||||
|
||||
关键配置项:赛事名称、副标题、主办方、Logo 路径、主题色、大屏轮播间隔、排名模式、默认积分模板、是否启用审核流。
|
||||
|
||||
### teams — 参赛单位
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | INTEGER PK | AUTOINCREMENT | |
|
||||
| code | TEXT | UNIQUE NOT NULL | 短代码,用于排序与导出 |
|
||||
| name | TEXT | NOT NULL | 全称 |
|
||||
| short_name | TEXT | | 大屏显示用 |
|
||||
| logo_path | TEXT | | 相对 `data/uploads/` |
|
||||
| color | TEXT | | 主题色,用于图表 |
|
||||
| sort_order | INTEGER | DEFAULT 0 | 自定义排序 |
|
||||
| active | INTEGER | DEFAULT 1 | 软删除 |
|
||||
|
||||
### athletes — 运动员
|
||||
|
||||
| 字段 | 类型 | 约束 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| id | INTEGER PK | | |
|
||||
| name | TEXT | NOT NULL | |
|
||||
| gender | TEXT | CHECK in ('男','女') | |
|
||||
| team_id | INTEGER | FK teams | |
|
||||
| employee_no | TEXT | | 工号/学号,可空 |
|
||||
| active | INTEGER | DEFAULT 1 | |
|
||||
|
||||
### sports — 大项
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| id | INTEGER PK | |
|
||||
| code / name / short_name | TEXT | |
|
||||
| scoring_profile_id | INTEGER FK | 该大项默认积分模板 |
|
||||
| sort_order / active | INTEGER | |
|
||||
|
||||
### events — 小项
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| id | INTEGER PK | |
|
||||
| sport_id | INTEGER FK | |
|
||||
| code | TEXT UNIQUE | |
|
||||
| name | TEXT | 如「男子100米」 |
|
||||
| gender | TEXT | 男/女/混合/不限 |
|
||||
| event_type | TEXT | individual / team / relay / match(球类) |
|
||||
| scoring_profile_id | INTEGER FK NULL | 覆盖大项模板 |
|
||||
| multiplier | REAL DEFAULT 1 | 权重,双倍项目填 2 |
|
||||
| record_eligible | INTEGER DEFAULT 1 | 是否参与纪录榜 |
|
||||
| status | TEXT | pending / ongoing / finished / published |
|
||||
| scheduled_at | TEXT | 计划时间 |
|
||||
| venue | TEXT | 场地 |
|
||||
| sort_order / remark | | |
|
||||
|
||||
### scoring_profiles — 积分模板
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| id | INTEGER PK | |
|
||||
| code | TEXT UNIQUE | |
|
||||
| name | TEXT | 如「田径前8名」 |
|
||||
| tie_mode | TEXT | skip / average / higher,默认 skip |
|
||||
| record_bonus_mode | TEXT | max / sum,默认 max |
|
||||
|
||||
### scoring_profile_rules — 模板明细
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| profile_id | INTEGER FK | 联合主键 |
|
||||
| rank | INTEGER | 名次 |
|
||||
| points | REAL | 分值 |
|
||||
|
||||
### entries — 报名项
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| id | INTEGER PK | |
|
||||
| event_id | INTEGER FK | |
|
||||
| team_id | INTEGER FK | |
|
||||
| athlete_id | INTEGER FK NULL | 个人项目 |
|
||||
| member_names | TEXT NULL | 团体/接力成员,JSON 数组 |
|
||||
| bib | TEXT | 号码/道次 |
|
||||
| seed | TEXT | 种子/预赛成绩 |
|
||||
| status | TEXT | registered / scratched / dq / dns |
|
||||
| remark | TEXT | |
|
||||
| UNIQUE(event_id, team_id, athlete_id) | | 防重复报名 |
|
||||
|
||||
### results — 成绩
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| id | INTEGER PK | |
|
||||
| event_id | INTEGER FK | 冗余,便于查询 |
|
||||
| entry_id | INTEGER FK UNIQUE | 一条报名项一条成绩 |
|
||||
| rank | INTEGER NULL | 名次,可空 |
|
||||
| result_text | TEXT | 展示用,如「1:06.33」「6.12米」 |
|
||||
| result_value | REAL NULL | 比较用(秒/米/分),用于排序与破纪录判断 |
|
||||
| unit | TEXT | s / m / pts / 次 |
|
||||
| is_tie | INTEGER | 是否并列 |
|
||||
| points_override | REAL NULL | 手工覆盖积分(需理由) |
|
||||
| status | TEXT | ok / dq / dns / dnf / withdrawn |
|
||||
| state | TEXT | draft / published ★ |
|
||||
| recorded_by / recorded_at | | |
|
||||
| verified_by / verified_at | | |
|
||||
| note | TEXT | |
|
||||
|
||||
### records — 纪录库
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| id | INTEGER PK | |
|
||||
| event_id | INTEGER FK | |
|
||||
| level | TEXT | meet / city / province / national |
|
||||
| result_value | REAL | |
|
||||
| result_text | TEXT | |
|
||||
| holder_name / holder_team_id | | |
|
||||
| achieved_at | TEXT | |
|
||||
| is_current | INTEGER | 是否当前有效纪录 |
|
||||
| source | TEXT | history(历届导入)/ current(本届产生) |
|
||||
|
||||
### record_breaks — 破纪录登记
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| id | INTEGER PK | |
|
||||
| event_id / entry_id | | |
|
||||
| level | TEXT | |
|
||||
| result_value / result_text | | |
|
||||
| bonus_points | REAL | |
|
||||
| state | TEXT | pending / approved / rejected |
|
||||
| approved_by / approved_at | | |
|
||||
|
||||
### score_ledger — 积分流水(核心)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| id | INTEGER PK | |
|
||||
| team_id | INTEGER FK | 归属单位 |
|
||||
| athlete_id | INTEGER NULL | 归属个人(个人榜用) |
|
||||
| event_id / entry_id / result_id | NULL | 溯源 |
|
||||
| source_type | TEXT | result / record_bonus / adjustment |
|
||||
| source_id | INTEGER | 对应来源记录 id |
|
||||
| points | REAL | 可正可负 |
|
||||
| voided | INTEGER DEFAULT 0 | 作废标记 |
|
||||
| voided_by / voided_at / void_reason | | |
|
||||
| created_by / created_at | | |
|
||||
|
||||
### point_adjustments — 人工调整
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| id | INTEGER PK | |
|
||||
| team_id | INTEGER FK | |
|
||||
| delta | REAL | 正负均可 |
|
||||
| category | TEXT | penalty / bonus / correction |
|
||||
| reason | TEXT NOT NULL | 必填 |
|
||||
| event_id | INTEGER NULL | 可选关联 |
|
||||
| voided / created_by / created_at | | |
|
||||
|
||||
### users / sessions / audit_logs / change_log
|
||||
|
||||
| 表 | 关键字段 |
|
||||
| --- | --- |
|
||||
| users | id, username UNIQUE, password_hash, display_name, role, active, last_login_at |
|
||||
| sessions | id, user_id, token_hash, expires_at, ip, user_agent |
|
||||
| audit_logs | id, user_id, action, entity_type, entity_id, before_json, after_json, ip, request_id, created_at |
|
||||
| change_log | id(version), entity_type, entity_id, action, payload_json, actor_id, created_at |
|
||||
|
||||
---
|
||||
|
||||
## 3. 排名如何算(性能与一致性)
|
||||
|
||||
数据量:单位 ≤50、小项 ≤100、报名项 ≤2000。**每次变更后全量重算**耗时可忽略(毫秒级),因此:
|
||||
|
||||
- 不引入复杂增量算法,直接 `SELECT ... FROM score_ledger WHERE voided=0 GROUP BY team_id` 聚合。
|
||||
- 排名结果可物化到 `standings_cache` 供大屏快速读取;缓存失效时以流水为准重算。
|
||||
- 一致性策略:**流水是唯一真相,缓存永远可重建**。任何「总分不对」的问题,重算一遍即可自愈。
|
||||
|
||||
---
|
||||
|
||||
## 4. 索引与约束
|
||||
|
||||
**索引**
|
||||
|
||||
| 索引 | 用途 |
|
||||
| --- | --- |
|
||||
| `entries(event_id)` | 按项目取报名项 |
|
||||
| `entries(team_id)` | 按单位取报名项 |
|
||||
| `results(event_id, state)` | 大屏取已发布成绩 |
|
||||
| `score_ledger(team_id, voided)` | 总分聚合 |
|
||||
| `score_ledger(source_type, source_id)` | 按来源作废流水 |
|
||||
| `change_log(id)` | 增量补发 |
|
||||
|
||||
**约束**
|
||||
|
||||
- `results.entry_id UNIQUE`
|
||||
- `scoring_profile_rules(profile_id, rank)` 联合主键
|
||||
- `PRAGMA foreign_keys=ON`
|
||||
|
||||
**删除策略**
|
||||
|
||||
- 业务数据一律**软删除 / 作废**,不做物理删除。
|
||||
|
||||
---
|
||||
|
||||
## 5. 迁移与初始化
|
||||
|
||||
- 迁移文件 `db/migrations/NNN_描述.sql`,按序号执行,记录在 `schema_migrations` 表。
|
||||
- 首次启动:建库 → 跑迁移 → 写入种子数据(默认管理员 + 默认积分模板 + 默认赛事配置)。
|
||||
- 默认管理员密码随机生成,打印到控制台,首次登录强制修改。
|
||||
Reference in new issue
Block a user