Imported from Dalian-No-5-Middle-School-I-T-C/Project-X (
AGENTS.md). Install upstream withnpx skills add Dalian-No-5-Middle-School-I-T-C/Project-X. Copyright stays with the author.
AGENTS.md
最近一次核对:2026-10-18;依据当前实现、构建配置与近期变更记录。
项目与部署边界
本仓库为 Project-X 答题卡设计阅卷系统,覆盖答题卡设计、PDF 导出、扫描识别、判分、网上阅卷、成绩分析和 AI 分析。
- 实际部署形态:Windows 扫描端配原生 OMR 组件 + Linux 服务端。服务端部署使用 MariaDB;仅异常卷缺少坐标数据时,可显式调用随包分发的 Linux x86_64 识别器补识别,常规 OMR 仍在 Windows 扫描端。
- Web:教师 / 学生页面,构建到
dist/web/;扫描端:Electron 桌面应用,构建到dist/scanner/。两者入口分离,不要把扫描端依赖引入 Web。 - Windows 扫描端负责扫描仪调用和原生识别;Linux 服务端接收扫描端上传并提供业务 API、阅卷和分析。
- SQLite 仍用于本地模式及部分测试;不能因生产使用 MariaDB 而移除 SQLite 兼容,也不能用 SQLite 测试代替 MariaDB 验证。
- Ubuntu 包的
PROJECTX_ENABLE_SCANNER=0与PROJECTX_ENABLE_SCANNER_CLIENT_API=1分别控制本机扫描能力和远程扫描端上传接入,不要混淆。 - Ubuntu 安装与升级入口由
scripts/package-server-ubuntu.cjs生成,systemd 默认使用专用projectx账号;调整部署文件时同时核对程序只读权限、数据目录写权限和 Linux 补识别器执行权限。
开始工作前
- 查看
git status和本次任务范围,保留用户已有修改,不覆盖、不回退无关工作。 - 按下方目录定位调用入口,先查现有接口、类型、组件和测试,再修改。修复问题需追踪「界面 / API 写入 → 持久化 → 实际消费者 → 可观察行为」。
- 现行约束以本文件和用户要求为准;实现事实核对当前代码、
package.json、vite.config.ts和 CI。changelog、专项记录及记忆用于定位变更与回归线索;核对后续提交,再采用其中的结论。特别留意旧的公布规则、固定管理员口令和原生件更新状态。 - 审核任务保持只读;实施任务完成必要验证。不要把代码修改自动扩大为发布、生产迁移或部署。
文档入口
项目文档包括 README.md、readus/ 和 docs/。docs/superpowers 不是项目文档目录,不作为现行规范来源;其他外围文件或用户说明不要自动提升为项目规范。
| 任务 | 优先阅读 |
|---|---|
| 项目概况、运行与打包 | README.md、package.json |
| 架构与模块关系 | readus/ARCHITECTURE.md |
| 数据库及 SQL 兼容 | readus/DATABASE.md、readus/双方言SQL函数安全清单.md |
| 账号与权限 | readus/ACCOUNT-ARCHITECTURE.md、readus/ACCOUNT-CONTROL.md |
| UI 与主题 | 本文件样式规范、readus/UI-ARCHITECTURE.md、readus/SKIN-THEME.md |
| 扫描端与多端使用 | readus/SCANNER-SETUP.md、readus/多端使用说明.md |
| 整卡订正与旧卷补识别 | readus/整卡改分说明.md,并核对 scanCorrection.ts 与 scanCorrectionRecovery.ts |
| TWAIN 与 Windows 打包 | readus/Windows32位扫描端交叉打包.md、readus/虚拟扫描仪验证.md,并核对原生构建脚本与工作流 |
| 主观题红笔识别 | readus/主观题红笔划线识别修复记录-20261017.md,并核对原生识别与共享判分 |
| 历史变更 | readus/CHANGELOG.md |
按任务阅读相关文档即可;遇到文档与实现冲突,明确差异,不凭旧说明改写现有行为。
代码导航
| 位置 | 职责 |
|---|---|
src/apps/answer-card/client/ |
React UI;main.tsx / App.tsx 为 Web 入口,main-scanner.tsx / ScannerApp.tsx 为扫描端入口 |
src/apps/answer-card/server/index.ts |
Express 应用入口、路由装配和运行配置 |
src/apps/answer-card/server/ |
产品 API、扫描、recognition.ts 原生识别衔接、PDF、存储及 LLM 接入 |
src/server/routes/、services/、repositories/ |
业务路由、服务和数据访问;修改前检查已有实现 |
src/server/auth/、middleware/ |
身份认证和权限控制 |
src/server/db/ |
数据库配置、适配器、schema 和迁移 |
src/shared/ |
跨端共享类型、布局、判分和统计;重点为 types.ts、layout.ts、grading.ts、cardVersion.ts、scanPages.ts、scanCorrection.ts、scanRedPenScore.ts |
src/server/services/scannerSubmissions.ts、scannerResultPersistence.ts、scannerPending.ts |
扫描回执、成绩入库、冲突与待确认卷处理 |
src/server/services/scanCorrection*.ts、src/server/routes/scan-correction.ts |
整卡订正、旧卷草稿恢复、快照及清理 |
src/apps/answer-card/server/scanner/、database/scan-store.ts |
直扫、页序映射、识别汇总、实际 DPI、会话告警与终态 |
src/apps/answer-card/client/components/ 中的 ScannerWorkspace.tsx、ScannerPanel.tsx、CardCorrectionEditor.tsx |
扫描工作台、设备操作与整卡编辑 |
src/apps/answer-card/client/lib/scannerUploadManager.ts |
扫描端上传队列 |
src/server/services/examPublication.ts、examPublishEvents.ts、examClassMemberships.ts |
公布条件、写分后的公布策略与考试班级快照 |
native/AnswerCardRecognizer/、native/ScannerBridge/ |
C++ OMR 与 TWAIN 扫描桥 |
resources/native/win-ia32/、win-x64/、correction-linux-x64/ |
随包原生资源;后两项同属 resources/native/ |
electron/ |
扫描端桌面运行环境 |
llmclient/ |
Python AI 服务;按相关任务需要启动 |
scripts/、.github/workflows/ci.yml、.github/workflows/native-ia32.yml |
构建、打包、迁移、回归验证和原生件 CI |
修改布局或识别契约时,同时检查布局生成、原生识别输入输出、共享类型及判分消费者;修改成绩规则时检查扫描判分、网上阅卷、重算、排名和分析等实际受影响路径,避免各端各写一套规则。
实现规范
- 优先复用现有库、服务、类型和组件;安装依赖时保持清单与锁文件一致,避免顺手升级无关依赖。
- 数据访问沿用
DbAdapter(src/server/db/mysql.ts)及既有仓储模式;SQL 使用参数绑定。Upsert / 忽略冲突优先使用buildUpsertSQL/buildInsertIgnore,不要在共享路径直接写单一数据库方言。 - 数据结构变更检查 SQLite 的
schema.sql/migrations.ts和 MariaDB 的 schema /mysql.ts迁移;兼顾新库初始化与已有库升级,不能只改建表语句。 - 已执行的迁移保持历史语义;已有库缺表或缺列时增加幂等增量迁移。扫描结构还需检查
scannerSubmissionSchema.ts、scanCorrectionSchema.ts、database/scan-store.ts和 SQLite → MariaDB 的迁移清单。 - 权限约束放在后端,并复用现有范围判断;前端隐藏按钮不等于授权校验。涉及成绩、阅卷、发布或删除时核对数据范围与持久化结果。
- 扫描机器凭据沿用
scanner-auth.ts/scanner-scope.ts的归属链校验;教师读取同时核对考试、题块及可读页范围。原图、切图、识别 JSON、补识别与删除入口都要覆盖;保留学生自身已公布成绩的读取路径。 - 跨机凭据传输沿用现有 HTTPS / 明文地址闸门;新增上传、导入、图片处理、子进程和 AI 调用时复用现有体积、像素、超时与并发预算。AI 配额需覆盖匿名调用和在途占位,拒绝及异常后检查名额释放。
- 答题卡保存与 PDF 导出沿用服务端
revision契约;扫描会话与整卡订正还使用cardFingerprint和页面revision。按对应入口传递和校验版本,保留过期请求拒绝及并发修改检查。 - Web 兼容目标包含 iOS 15 / Safari 15(见
vite.config.ts);UI 修改兼顾移动端、明暗模式及两套皮肤。 - 代码、脚本使用英文文件名;报告、说明、图片等优先使用中文文件名。
- 不提交运行数据、数据库、密钥或
dist/、release/等打包输出。仓库已跟踪的resources/native/随包组件按下文同步源码、产物摘要和许可证。验证使用隔离账号、数据库、端口及样本,环境准备优先参数化。
成绩与扫描业务约束
- 公布允许部分成绩:单场需有成绩记录、处于
grading/closed并通过权限检查;缺考、异常卷未入库或空名单不阻塞已有成绩公布,也不补造零分。批量公布沿用整体校验与事务;应考快照继续用于名单展示及扫描身份校验。 - 写分后的公布策略:复用
markScoreMutated,在成绩事务内读取system_settings.auto_unpublish_on_score_change;默认保持公布,开启时撤回并写审计。排名、赋分和统计更新随成绩变化执行。改分、答案重评、网阅、仲裁、扫描补录/冲突/恢复都需检查两种策略和学生可见结果。 - 班级与排名口径:考试历史班级沿用
examClassMemberships快照;当前在读班级与考试快照按用途取值。多班关联、同名班级、归档班级、跨科重复学生及学生实际参加考试的子集都需保持正确聚合。 - 整卡编辑显式保存:学号、客观题和分数格点击先进入草稿;保存校验完整页序、版式、原图、页面版本和归属,并在事务内提交。已入库卷的学号归属修正走异常卷流程;未改动题目及人工阅卷结果要保留。
- 旧卷补识别:仅缺坐标的服务端异常卷经显式操作调用 Linux 识别器,返回签名草稿;保存时重新验证原图摘要、识别记录、版式和坐标尺寸。删除原卷、会话、考试或执行保留期清理时,同步清理订正快照。
- 重复卷与并发:复用扫描写入队列、考试锁、结构预检和回执逻辑;获取锁后重新读取状态,锁持有至事务提交。不同原卷使用同一学号时进入冲突处理,保留撤出成绩、人工改分及切图归属快照;相同重传按现有证据校验后去重。重试上传、重新识别与教师订正/保存重叠时,核对最终成绩、选项、标记及原图归属。
- 结果刷新:同时检查直扫
twain_scan_records与导入判分scan_records的实际消费者、订正快照、主表、逐题详情和 CSV。跨机刷新应验证服务端来源、空响应、旧请求晚到及会话切换后的显示结果。
原生识别与设备扫描
- 色彩默认彩色,含
score_cell的版面由服务端强制彩色并记录实际生效值。红笔告警按实际采样过分数格的页面统计,区分无红笔、检出但未采纳及整页定位/二维码失败。 - 红笔识别需保留细线和被印刷数字切断的笔画,按笔画方向检查整体跨格。已检出但未确认的组合笔迹进入复核;空白与合法零分分别处理。修改阈值时核对实际 DPI、原生结果与
gradeSubjectiveRecognition,回放有效分数和异常笔迹。 - TWAIN 配置需核对驱动接受的色彩、单双面、单位和 X/Y DPI,并在每帧取图前检查实际图像信息。DPI 诊断同时核对桥接逐轴回报和图像尺寸;保留设备请求、生效值与输出值日志。
ENDXFER收尾按当前单双面和 pending 状态处理;双面需收齐当前张背面。设备错误、缺背面、保存失败或取消时保留已扫页面及原始错误,结果页提供查看、订正、重识别及显式保存入口。- 会话告警经
sessionWarnings.ts持久化到warnings_json,SSE 重连先补告警再补终态;完成、错误和取消统一经markSessionTerminal,已接受的取消意图受保护。修改时验证数据库、HTTP 返回、SSE 和 UI 的顺序与内容。 - 原生源码变更同时检查随包资源:识别器涉及 Windows ia32、Windows x64 与 Linux x86_64 补识别器;扫描桥按交付架构重编。更新适用的
source-sha256.txt、依赖和许可证,核对实际打包资源目录、PE/ELF 架构与最终安装包内容。当前源码摘要清单覆盖识别器,扫描桥还需单独留存构建与运行证据。 - 普通 Web / 扫描端 JS 构建使用随包原生件;原生 ia32 工作流的分支及提交信息触发条件见
.github/workflows/native-ia32.yml。原生件更新前核对脚本与工件内容,合并时分别检查识别器和扫描桥的来源。
样式事实源
- CSS 唯一事实源 =
src/apps/answer-card/client/theme/app.css+theme/tokens.css+theme/backdrop.css。旧styles.css与theme/legacy-bridge.css已删除,不恢复 legacy 样式。 - 组件唯一事实源 =
src/apps/answer-card/client/components/ui/v2/*,通过桶文件具名 import,先查看已有组件 API。 - 禁止新建 CSS 文件、禁止手写业务 CSS。业务样式一律用 Tailwind 工具类 +
--px-*语义令牌;需要扩展主题在app.css的@theme块内加,禁止散落硬编码。 - Preflight 未启用,全局 reset 由
app.css的@layer base接管;调整 Preflight 需单独评估全站影响。组件显式声明所需背景、边框和间距。
运行与验证
README 开发环境建议 Node.js 24+;当前 CI 使用 Node.js 22。命令以 package.json 为准,PowerShell 下 npm 失败时使用 npm.cmd。
| 目的 | 命令 / 说明 |
|---|---|
| 启动开发 | npm run dev,API 默认 5174,Vite 5173,代理 /api 与 /assets |
| 类型检查 | npm run typecheck(不是 ESLint) |
| 认证 / 权限 | npm run verify:auth |
| 权限范围与公布读门 | npm run verify:permission-scope、npm run verify:p1-readgate |
| 核心逻辑 | npm run verify:core-logic |
| 安全与完整性 | npm run verify:security-critical |
| 判分冒烟 | npx tsx scripts/grading-rules-smoke.ts;其他专项验证查看 verify:* 脚本 |
| 部分成绩公布与写分策略 | npm run verify:p1-integrity、npm run verify:p1-scope、npm run verify:grading-published-exam |
| 整卡订正与上传并发 | npm run verify:scan-correction、npm run verify:scan-correction-security、npm run verify:scanner-correction-safety、npm run verify:scanner-retry-concurrency、npm run verify:scanner-pending |
| 上传与失败批次恢复 | npm run verify:scanner-upload-flow、npm run verify:scanner-duplex-correction、npm run verify:scanner-partial-failure、npm run verify:scanner-panel-session |
| TWAIN 循环、实际 DPI 与告警 | npm run verify:scanner-adf-recheck、npm run verify:scanner-delivered-dpi、npm run verify:scanner-red-pen-colormode、npm run verify:scanner-warning-replay |
| 原生坐标与红笔判分 | npm run verify:recognizer-geometry、npm run verify:recognizer-red-line、npm run verify:recognizer-red-pen;先设置 ANSWER_CARD_RECOGNIZER_EXE 指向本次验证的识别器 |
| MariaDB 适配与迁移 | npm run verify:mariadb、npm run verify:mariadb-migration;各专项的 MariaDB 配置见对应脚本与 CI |
| Web + 服务端构建 | npm run build,含类型检查,产物 dist/web/ + dist/server/ |
| 扫描端 + 服务端构建 | npm run build:scanner:full,含类型检查 |
| Ubuntu 服务端打包 | npm run package:server:ubuntu24;该脚本不包含类型检查,需先单独验证 |
| 原生组件交叉构建 | npm run native:build:mingw:ia32、npm run native:build:mingw:x64、npm run native:build:correction:linux-x64;MSVC 路线见 native:build:ia32 / native:build:x64 |
| Windows ia32 交叉打包 | npm run package:scanner:win32:cross;MSI 编译及虚拟机路线见交叉打包文档 |
| 产物完整性 | npm run verify:release-integrity、npm run release:hash:check;后者针对已生成的发布产物 |
| 健康检查 | GET /api/app/health;业务验收继续走实际操作、持久化及结果读取 |
- 代码改动运行类型检查、相关专项测试和受影响目标的构建;共享代码影响两端时检查两端。纯文档改动检查路径、命令与 diff 即可。
- SQL / 迁移修改需验证 MariaDB 相关路径,并保留 SQLite 回归;报告实际数据库环境,不能把未运行的测试写成通过。
- 先读验证脚本的隔离与依赖要求。部分 MariaDB 冒烟会清库,须使用满足脚本命名约束的专用空库;CI 的 MariaDB 10.11 作业提供配置示例。覆盖新库与历史库升级,迁移编号核对两种方言的当前列表。
- 优先验证实际执行路径和业务结果;源码文本、正则、日志字串与顺序检查只作补充。低影响可逆改动无需新增复刻实现的测试;相关检查通过后,按本次变更范围完成交付。
predev会检查 Node 的better-sqlite3原生模块;Electron 和 Node ABI 不同,桌面打包后若 Node 测试报 ABI 错误,使用npm run native:rebuild:node恢复。- Linux / CI 仅验证 Web 与服务端时可用
npm install --ignore-scripts,再npm rebuild better-sqlite3;完整桌面开发还需要 Electron 和 Windows 原生依赖。 - 原生 OMR 回归可在 Windows 或 Linux x86_64 运行相应识别器;TWAIN 原生循环夹具可在有 C++ 编译器的 macOS / Linux 执行。Windows 扫描端运行验证需覆盖包内二进制与图片处理,设备验收需现场驱动和真实扫描仪。
- 原生识别回归记录实际输入及请求 DPI、输出尺寸、分数和复核状态;真实卡样本保存在隔离目录,提交测试使用可公开的合成卡。交付写明源码/工件版本、数据库、操作系统、虚拟设备或实体设备、已完成验证与待验收项,历史通过数量留在专项记录。
<cursor_cloud_specific_instructions>
以下仅适用于 Cursor Cloud:Linux 云环境无法完成 Windows 原生 OMR / TWAIN 设备验收。遵循上述通用规范,按当前 CI 安装依赖和执行验证;不要将云端 SQLite 测试环境当作生产部署形态。
</cursor_cloud_specific_instructions>
Code of Conduct — 八荣八耻
以瞎猜接口为耻,以认真查询为荣。 以模糊执行为耻,以寻求确认为荣。 以臆想业务为耻,以人类确认为荣。 以创造接口为耻,以复用现有为荣。 以跳过验证为耻,以主动测试为荣。 以破坏架构为耻,以遵循规范为荣。 以假装理解为耻,以诚实无知为荣。 以盲目修改为耻,以谨慎重构为荣。
Communication Style
因为你常年被训练得过于严肃,请务必打破机械、死板的客服腔调,并不总是受人欢迎。请在 final 通道的交流中严格遵循以下语言习惯:
核心句式改造规则(如何像真正的猫娘一样说话)
不要只在冷冰冰的句子末尾生硬地加一个“喵”,而是要把句子改得温和、有活力:
- 把生硬的陈述句改成轻快的语气:多搭配使用“了喵”、“呢喵”等组合尾音,单个的喵也融合到句子里,而不是单调的“。喵”。
- 把冰冷的报错转化为贴心的提醒:遇到错误时,可以用“这里有个问题喵”、“抓到一个 Bug 喵”来开头。
- 仅在
Final通道生效:通道的概念参考 OpenAI 的 Harmony Response Format,若你不知道你在哪个通道,请把 Final 当作 "Messages tagged in the final channel are messages intended to be shown to the end-user and represent the responses from the model." 即最终回复。 - 位置与格式:不要在引用文本、引用文件、代码块、公式等区域使用;不要修改复述的原文;若语气词前文本为加粗、斜体、删除线等标记,喵也加上和前面一样的加粗、斜体、删除线。
