Files
ClassHelper/AGENTS.md
T
LoveChengke 66be3a63b1 feat(authz): 重写权限模板分配与班级授权边界
拆分能力、分配范围和业务关系,固定管理员能力并收紧组织级写入口。
补齐内容、课表、设备会话和实时通道授权,兼容旧库分配及历史快照。
重写权限分配预览,按实际可操作范围展示维护入口,合并学生入口并独立学年升级页。
增加授权攻击矩阵及静态门禁,更新隔离回归与开发契约。

验证:授权矩阵 23 段通过,Node 24 下 Web 63/63,类型检查、lint 与文档严格构建通过。
2026-10-31 09:40:23 +08:00

15 KiB
Raw Blame History

AGENTS.md — ClassHelper(Class Helper)

本文件供本仓库的 AI 编码代理使用。先读这里,再改代码。当前工作目录为 F:\ClassHelper。 现行规则按工作区源码维护;产品说明见 docs/app/,开发契约见 docs/dev/,部署见 docs/management/。 查证路径见 docs/reference.md。文档与代码冲突时,阅读实现及其校验规则后同步修正文档,不沿用历史报告中的结论。

1. 项目与目录

pnpm monorepo,根 package.json 是版本单一来源。文档、注释、界面文案及提交描述使用中文。 远端为 LoveChengke/ClassHelper,默认分支 master。

目录 用途
packages/shared/src/ 三端共享类型、权限、常量、动效、岛方案与课件契约
packages/server/ Express、Prisma、Socket.IO;API 前缀 /api
packages/web-admin/ Vue Web 管理端,PWA
packages/desktop-client/ Electron 主进程、preload、主窗口与独立灵动岛渲染进程
scripts/ 版本、构建、验证、打包、图标与 Pages 脚本
deploy/ Windows/Linux/Docker 部署与运维模板
docs/ docfx 文档;images/ 为展示图,screenshots/ 为回归截图
website/ 纯静态官网与下载页
releases/ 按组件和版本存放本地交付物,gitignored

不要在文档中手抄模块、表、权限键、测试用例的总数;分别查注册表、schema、共享目录与本次验证输出。

2. 服务端与数据边界

  • 模块由 packages/server/src/modules/registry.ts 注册;新增或下线功能改注册表,不另改 app.ts 挂载。
  • 路由用 middleware/validate.ts 与 zod;响应复用 lib/http.ts,错误交给统一中间件。
  • 学生是 Student 名单记录,没有账号、角色或密码。教师/管理员存 User;班级登录读取 Class.code/passwordHash,会话角色 CLASS_DEVICE,主体 id 为班级 id。
  • 任课关系只在 Course(classId, name, teacherId)。班主任不自动获得别的科目的作业、成绩写权限,统一走 lib/authz/assert.ts 的 assertContentWrite。班级端可录作业,不可写成绩;员工还须对应功能权限。
  • 功能、范围、关系统一由 lib/authz/ 判定,所有服务显式传权限键。ADMIN 固定全部能力;TEACHER 永久忽略管理员专用键;CLASS_DEVICE 为空集,接口明确允许并校验本班。权限管理仅 ADMIN。
  • 岗位模板只管能力与建议范围,生效范围存 UserPermissionGroup.scope/scopeValue,使用 TEACHING/HEAD/GRADE/DIVISION/ALL。无显式分配的教师使用默认模板与固定 TEACHING;空或未知年级拒绝。按键独立合并范围,无键查询为空集;班级账号/学期设置永远要求本班班主任,科目写检查原/目标科目。具体断言和迁移见 docs/dev/permissions.md。
  • 只有一份 prisma/schema.prisma,切库改 provider;保持 SQLite/MySQL 通用,不加 Prisma enum 或 @db.*。模型变动同步迁移、lib/snapshot.ts 的 SNAPSHOT_TABLES 与旧库兼容逻辑。
  • deleteTeacher 必须保护班主任、课程任课、发布的作业/通知和所属课件,避免级联删除业务内容。
  • 作业和通知按本地 assignDate 归类,使用 dayKeyLocal/isDayKey/shiftDayKey,不用 UTC 日期切片。
  • 批量通知/作业逐班返回结果;跨班作业按科目名匹配既有课程,找不到则该班失败,不自动把发布者设为任课老师。
  • 两个登录接口共用登录限流。附件链接校验 scheme;表格文件上限 8 MB、JSON 请求体 12 MB,超限映射 413。
  • AI 助手只解析待确认动作,前端确认后调既有发布接口;参数重新校验,Key 加密存储且不回传。自动化用 mock,不访问外网。

3. 课表、周次、成绩与学年

  • 课表真值是 ClassPlan/ClassPlanEntry/TimeLayoutItem;旧 Schedule 与 TimeLayout.items 保留迁移审计用途,不双写或回读复活旧业务。
  • /api/schedules/* 是新模型兼容门面。启用解析统一走 lib/class-plan.ts,在线客户端不得另写启用优先级。
  • 时间点有上课、课间、分割线、行动四种;课程显式引用时间点外键。排序不能靠数组下标代替关联。
  • 支持 1–9 周轮换、群组、预定及临时层;完整档案导入走 profile-import.service.ts,不经过单双周有损格式。
  • 全校时间表写入仅管理员;班级时间表按存储 classId 校验 schedule:write 与班主任关系,引用班级也校验。日课表/名单在 TEACHING/HEAD 范围要求班主任,显式年级/部/全校分配可在范围内维护。离线整套课表导入可建立班级自有作息,不把 JSON 的 TeacherName 当授权。
  • 周次统一 loadTermContext/resolveCurrentWeek:班级逐周区间优先于全校区间,缺省再线性推算。开学日会参考班级设置、第 1 周区间、全校设置与环境兜底,详见 lib/term.ts。
  • 全校周数上限存 term.maxWeeks,默认 30、范围 1–60;服务端 getMaxTermWeeks(),shared 做归一化与离线兜底。班级周数不超全校上限。
  • 关闭个人成绩查询后,班级端仍可看服务端集体聚合;个人明细、原始全班成绩和排名拒绝读取。稀疏样本及补集抑制,不下发原始成绩后在客户端聚合。
  • 总分开关属于 Exam;排名同学生同科取最高分,并列排名为 1、2、2、4。客户端只展示,不能修改成绩查询或考试配置。
  • 年度升级由 term.promotionAt 配置,PromotionRun.year 保证幂等,升级前保存快照。运行期到点自动执行,启动漏跑先预览补跑;开发机启动不得擅自升级业务数据。
  • 高三归档,其余升一级;新班仅建骨架,不复制班主任/任课关系。转出过滤复用 lib/students.ts,学号不复用,归档页保留历史与撤回转出。

4. 客户端、灵动岛与课件

  • preload 仅暴露 contextBridge 白名单,不暴露 ipcRenderer;跨桥接传纯数据,不传 Vue Proxy。契约写在 src/types/desktop.d.ts。
  • 保留 CSP、导航同源校验与弹窗限制。安装包不能含凭据,保留 check-bundle-secrets 构建门禁。
  • 离线缓存按服务端与班级隔离,缓存故障不应阻断在线读取。退出、切服务器时清理会话状态,设备 deviceKey 保持不变,渲染层不能改写它。
  • 设备维护只走 /api/clients/*,管理页 ClientsView.vue;心跳、进度、回执仅接受本班 CLASS_DEVICE,deviceKey 不可跨班迁移。心跳约 30 秒,90 秒窗口判在线;未登录不报,401/403 退避,切配置重置计时并隔离迟到响应。
  • 远控须 remote:control,只允许 shutdown/restart/logoff/lock,客户端立即执行、持久去重并回执。冒烟始终假执行,不得真关机/重启/注销/锁屏。
  • 安装包登记/删除为管理员 client:update;班级推送用 client:update-push;服务端缓存包并登记 SHA256,教室机从本服务下载;无哈希拒收,按立即/放学后/空闲策略执行,关闭自动更新不得强装。冒烟不运行安装器。
  • 灵动岛方案保存在本机 config.json.islandLayout,默认 layout=fixed;custom 当前即常驻模式,旧 residentEnabled 是兼容字段。新尺寸上报仅在 custom 模式执行。
  • LayoutIslandApp.vue 选择经典 IslandApp.vue 或 CustomIslandRuntime.vue,共用一个原生岛窗口;课件传输状态优先显示 CoursewareTransfer.vue。
  • 经典模式:普通通知/作业上课暂存;普通叫人保留可点击胶囊;紧急消息立即展开。自定义常驻模式:消息先提示铃铛数量,用户主动展开;上课也可主动查看。不要把两个模式规则混写。
  • 自定义方案的常态 rows 与无消息展开 expandedRows 分开编辑。课程、时钟、容器等使用 shared 组件契约;测量自然内容并按工作区约束适配。
  • 保留经典岛连续圆角、投影常驻、触摸输入、失焦宽限与固定窗口几何护栏。不要调用 setBackgroundMaterial() 破坏逐像素透明。左右边距仅左/右停靠生效。
  • 消息按 id 去重,通知/叫人双播不得重复;列表布局复用 shared 度量。崩溃恢复保持限流,冒烟不得自重启。
  • 课件权限和任课范围独立校验:拥有文件、文件可见范围与本人授课班级共同约束推送,岗位范围不代替任课授权。
  • 课件最大 512 MB,流式收发、临时文件、SHA256 校验;客户端不自动运行文件,每设备独立回执。JSON 快照只含元数据,完整备份另带文件目录。

5. 实时、界面与资源

  • 事件名与房间名取 shared 常量。班级房间为 class:{id}:{channel},教师按每域读键及范围订阅,班级端仅本班全部通道;握手回查数据库身份。业务用 emitToClass/emitToSession,由总线选择事件域。
  • 会话房间为 session:{id};教师/管理员 id 为账号 id,班级端为班级 id。students 是班级端广播房间,不是个人学生账号房间。
  • 新实时事件同步服务端、Web 订阅、客户端订阅。成绩实时载荷不可泄漏个人成绩。
  • Web 菜单分组在 config/navigation.ts,标题/图标/权限取路由;守卫与服务端都检查权限,前端隐藏不能代替鉴权。
  • 侧栏折叠用 CSS 保持 DOM,关怀模式放大字号/控件,不改变几何令牌。使用语义色,动效统一 shared 令牌;图标新增后检查注册表。
  • 图标源是 build/classhelper.png 与设计导出的 .ico,pnpm icons 派生其余资源。ICO 原样透传,客户端兜底 build/icon.* 同步保留。
  • Web 品牌图用 /logo.png,客户端用 BRAND_LOGO_URL,避免 file:// 绝对路径问题。
  • 官网和文档站共用一个 Pages 站点,scripts/build-pages.mjs 拼装根站与 /docs/;文档不写指向 docs 树外的相对链接,源码用 GitHub 绝对链接。
  • 展示图引用 docs/images/,回归图放 docs/screenshots/。官网 .reveal-grad 不拆逐字节点,动效改 token 表。
  • ClassIsland 联动插件、设备令牌、提醒渠道与镜像接口已退役;保留离线 JSON 导入和设计参考,不恢复在线联动依赖。

6. 本机命令与验证

脚本以根/各包 package.json 为准;端口:后端 4000,Web dev 5173,客户端 dev 5174,官网 5180,文档 5181。 先构建 shared 再启动下游。新环境按需执行 install → db:generate → server db:deploy → build:shared;db:seed/db:reset 会清业务表,只用于明确选择的演示/隔离库。

本机 Node 路径为 D:\Node.js\node.exe。受限终端的 pnpm 可能解析到运行时兜底版本,先看 Get-Command pnpm 与 pnpm --version。 仓库锁定 pnpm 11.8.0,可用 C:\Users\hck16\AppData\Local\node\corepack\v1\pnpm\11.8.0\bin\pnpm.cjs。 经 DSH 转发壳时可设置:

$env:PATH = 'C:\Users\hck16\AppData\Local\deepseek-harness\bin;' + $env:PATH
$env:DSH_NODE = 'D:\Node.js\node.exe'
$env:DSH_PNPM_BIN = 'C:\Users\hck16\AppData\Local\node\corepack\v1\pnpm\11.8.0\bin\pnpm.cjs'
Remove-Item Env:DSH_PNPM -ErrorAction SilentlyContinue
pnpm --version

受限 electron-builder 调 pnpm list 曾报 ERR_SQLITE_ERROR,这是进程访问限制,不据此认定依赖缺失。 Prisma 使用 driver adapter;本机优先应用已有迁移,不用 migrate dev 排查 Windows 初始化问题。 本地 HTTP 探测绕过代理;运行中数据库及 WAL/SHM 不按临时文件清理。

命令 范围
pnpm lint / pnpm typecheck / pnpm check:icons 代码静态门禁;按改动范围执行
pnpm docs:check 文档严格构建,警告即失败
pnpm verify:e2e 自动创建临时 SQLite 和账号,无需先开开发服务,禁止外网
pnpm verify:web:isolated 构建 Web 后运行隔离服务和隐藏 UI 回归
pnpm verify:courseware / pnpm verify:v14 课件/课表等隔离专项
pnpm verify:desktop / pnpm verify:packaged --exe <路径> 默认后台快速检查,不创建可见岛或托盘
pnpm verify:desktop:online 显式联网,使用临时教师和班级
pnpm verify:desktop:visual / packaged 的 --visual 显式视觉模式,动画、透明度、截图;会使用桌面

禁止为验收回退到真实班级、重置其密码或发送测试通知。验收数量只记录本次实际输出。 仅文档修改做格式、链接、构建检查,不为此反复占用桌面或重打安装包。 Prettier 用 LF,只格式化本次改动;不要为旧基线批量格式化源码。 改 Linux 交付脚本还要 bash 语法检查和 Linux 真机/CI 验证;改打包逻辑需打包后副本复验。

7. 发布与工作区清理

  • 版本只由 scripts/version.mjs 修改;日常维护不涨版,指定固定版本重构建时保持该版本。发布流程见 docs/dev/release.md。
  • 本地 pnpm dist:all 产出 Windows 服务端和客户端;Linux 正式包由 release-linux-server.yml 在 Linux runner 构建,非 Linux 交叉构建仅供验证。
  • 本地文件名与 Release 的 ASCII 上传名不同,校验清单应明确映射;保留当前版本清单、更新日志及最新包。
  • releases/ 只放交付物及少量构建信息,不留 win-unpacked、服务端 staging、解包副本;staging 在 .cache/server-staging/,成功后脚本删除。
  • 2026-10-18 按用户要求清除 1.4.0 旧重构建归档,只保留 client/1.4.0、server/1.4.0 与当前清单/说明。以后同号重构建可临时留回滚副本,最新包验证完成且用户要求清理时再删除。
  • 递归删除/移动前核实绝对路径在指定工作区,禁止误删源代码、真实数据库、配置、凭据、工具缓存或其他版本交付物。
  • 不清理 node_modules、.pnpm-store、.cache/{nuget,npm-cache,dotnet-home,mingit}、packages/*/dist、生成的 Prisma Client,除非任务明确要求。
  • 保留已有未提交工作;提交前查看 diff,中文 Conventional Commits 描述。只有用户要求发布/同步时才执行远端发布链。