1
Architecture
biss edited this page 2026-07-24 12:00:48 +08:00
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.

系统架构

衡准考试信息管理系统采用 ASP.NET Core 10 模块化单体架构。生产环境部署一个 Eis.Web 进程,前端静态资源和 API 由同一宿主提供;数据库维护工具 Eis.Tools 独立发布。

1. 总体结构

浏览器
  ├─ Vue 3 单页应用
  ├─ 公开页面 / 考生中心 / 管理后台 / 招生学校端
  └─ PDF 文书生成模块
          │ HTTPS / JSON / Cookie
          ▼
Eis.WebASP.NET Core
  ├─ 静态资源与 SPA History 回退
  ├─ Minimal API 端点
  ├─ 身份识别、角色与数据范围校验
  └─ 健康检查
          │
          ▼
Eis.Application
  └─ 应用服务契约
          │
          ▼
Eis.Infrastructure
  ├─ 业务服务与仓储
  ├─ SQLite / MySQL
  ├─ Redis / 本机缓存
  ├─ Redis / 内存认证状态
  ├─ ClosedXML
  └─ 安全与防伪服务

2. 项目依赖

Eis.Domain

领域层保存稳定业务概念和值,不包含 Web、数据库或前端细节。

Eis.Application

应用层以接口描述用例,包括:

  • 认证;
  • 考生服务;
  • 公开查询;
  • 管理中心;
  • 组织、账号、配置;
  • 考试、编排、成绩;
  • 审批、招生和录取。

端点依赖这些契约,而不是直接依赖数据库实现。

Eis.Infrastructure

基础设施层实现:

  • 关系数据库连接和初始化;
  • 管理员、考生、招生业务仓储;
  • 缓存和会话状态;
  • 密码、TOTP 和文书防伪;
  • Excel 读写;
  • 准考证、成绩单和录取通知书数据;
  • 审批流、统计和投档业务。

部分大型业务通过同名 partial 类拆分文件,例如考生服务和招生服务,以保持单个文件可维护。

Eis.Web

Web 层负责:

  • 加载 .env 和运行环境;
  • 组合依赖注入;
  • 初始化数据库;
  • HTTP 输入输出;
  • 获取当前身份;
  • 注册安全响应头;
  • 健康检查;
  • 静态资源;
  • SPA 路由回退。

复杂业务规则应留在 Infrastructure 的应用实现中,而不是放在端点委托。

Eis.Tools

数据库工具复用 Infrastructure 的数据库选项、初始化和维护服务,提供:

  • database init
  • database reset
  • database seed

工具可以和 Web 一起发布,但执行时不要求 Web 正在运行。SQLite 数据维护时反而应先停止 Web,避免并发写入。

3. HTTP 与前端

API 域

前缀 面向对象
/api/public 未登录访客
/api/auth 注册、登录、密码、TOTP、退出
/api/candidate 当前考生
/api/admin 超级、校级、班级管理员
/api/admission 当前招生学校

未注册的 /api/* 由统一兜底端点返回 JSON 404,不会回退成 HTML,也不会转发到旧 Node.js 服务。

SPA 路由

前端使用 Vue Router History 模式:

  • /candidate/...
  • /admin/...
  • /admission/...

开发时由 Vite 提供页面并代理 API;生产时 ASP.NET Core 提供 wwwroot/vue-app,对非 API 语义 URL 返回前端入口。

会话初始化

前端进入路由前加载当前会话:

  1. 未登录访问受保护页面:跳转登录页并携带返回地址。
  2. 已登录但角色不匹配:返回该角色首页。
  3. 考生必须改初始密码或资料未完成:跳转首次登录流程。
  4. 会话失效:重新登录,而不是假定刷新可恢复。

4. 认证与授权

凭据

  • 密码使用 PBKDF2 加盐哈希。
  • TOTP 密钥使用 TOTP_ENCRYPTION_KEY 派生的材料,以 AES-256-GCM 加密保存。
  • 恢复码只保存带服务端密钥的哈希。
  • 登录状态通过 HttpOnly、SameSite Cookie 标识。

状态存储

未配置 Redis时:

  • 登录 Session:进程内内存;
  • TOTP 登录挑战:进程内内存;
  • TOTP 绑定临时状态:进程内内存;
  • 进程重启后需要重新登录。

配置 Redis 时:

  • 普通缓存通常使用 DB 0
  • 认证状态默认自动使用 DB 1
  • 也可用 REDIS_SESSION_URL 指向独立 Redis
  • 系统拒绝让普通缓存和认证状态使用同一端点的同一逻辑 DB。

明确配置的认证 Redis 连接失败会阻止服务启动,避免多实例部署时静默退回本机内存。

数据范围

授权是多维度的:

角色
  └─ 管理级别
      └─ 学校
          └─ 班级
              └─ 具体业务状态

招生学校角色另按自己的学校 ID 限制计划、投档和报到数据。投档材料不会包含考生的其他志愿。

5. 数据持久化

双数据库适配

  • SQLite:本地开发、自动化测试、单机和默认 Docker 部署。
  • MySQL 8.4:生产、多实例或独立数据库部署。

两种数据库共享同一业务服务,并分别使用内嵌 schema SQL。数据库结构版本记录在 schema_metadata,当前为 v20。

总表与专属分表

系统采用“总表索引 + 独立物理分表”:

  • 创建考试时建立:
    • exam_<partition>_candidates
    • exam_<partition>_admissions
    • exam_<partition>_results
    • exam_<partition>_centers
  • 创建学校时建立:
    • school_<partition>_students

分区键由业务 ID 的 SHA-256 摘要生成,不直接拼接用户输入。总表继续承担跨考试、跨学校查询和外键完整性,专属表支持按业务对象组织数据。

事务与审计

以下操作强调原子性:

  • 报名号批量生成;
  • 批量成绩确认写入;
  • 成绩复议改分和相关结论;
  • 招生投档与正式录取;
  • 业务写入和审计日志。

批量操作失败时应整体回滚,避免半批状态。预览类操作不得开启正式写入。

6. 数据库状态快照

关系表读取会在进程内复用只读快照,避免每个请求重复扫描和转换全部业务数据。

  • 应用自身写入:立即使快照失效。
  • SQLite:通过 PRAGMA data_version 识别其他连接的提交。
  • MySQL 外部直写:默认最多延迟 DATABASE_STATE_CACHE_TTL_MS 后可见。

因此不建议绕过应用直接写数据库。除审计缺失外,外部直写还可能造成短时间读到旧快照。

7. 应用缓存

缓存命名空间:

  • public:首页和已发布公告;
  • results:考生已发布成绩。

特性:

  • Redis 可选;
  • Redis 不可用时回退到有界本机缓存;
  • 热点请求合并,避免同一 key 并发回源;
  • 通过命名空间版本做批量失效;
  • 写入后主动失效。

公开缓存默认 60 秒,成绩缓存默认 24 小时。本机缓存默认最多 200 条。

8. Excel 和 PDF

Excel

ClosedXML 在服务端生成和解析工作簿。导入一般遵循:

下载模板
  → 填写
  → 上传
  → 逐行校验
  → 页面预览
  → 明确确认
  → 事务写入

这保证文件解析错误不会产生部分业务写入。

PDF 文书

成绩单和录取通知书在浏览器端下载 PDF,数据由服务端按当前身份和发布状态提供。文书包含:

  • 防伪查询码;
  • 二维码;
  • 公开验真地址;
  • HMAC 签名。

验真服务只返回允许公开核对的信息。

9. 健康检查

/health/live

用于容器和进程存活检查,返回服务名和框架。

/health/migration

用于诊断:

  • 旧 API 已移除;
  • 原生认证、考生和管理模块状态;
  • 缓存 readydisabledunavailable
  • 认证状态使用 redismemory
  • 当前启用的原生能力。

该路径名保留了迁移阶段语义,但当前系统已经完全运行于 ASP.NET Core。

10. 部署模型

单机

Eis.Web + SQLite + 内存会话/缓存

适合开发、演示和低并发单实例。

生产

一个或多个 Eis.Web
        ├─ MySQL 8.4
        ├─ Redis 缓存 DB
        └─ Redis 认证状态 DB/实例

多实例必须共享认证状态。静态资源包含在每个 Web 发布物中,不需要独立 Node.js 服务。