Files
NextEdu/docs/architecture/audit/archive/files-audit-report.md

30 KiB
Raw Blame History

文件模块审计报告

审查日期2026-06-25 审查范围:src/modules/files/**src/app/api/upload/**src/app/api/files/**src/app/(dashboard)/admin/files/**src/modules/settings/actions-avatar.tssrc/modules/settings/components/avatar-upload.tsx 架构图参考:docs/architecture/004_architecture_impact_map.md §2.17、docs/architecture/005_architecture_data.json


一、现有实现概要

1.1 文件分布

路径 文件数 说明
路由层 - 上传 src/app/api/upload/route.ts 1 FormData 接收 + 直接写磁盘 + DB 落库
路由层 - 单文件 src/app/api/files/[id]/route.ts 1 GET 查询单文件、DELETE 删除单文件
路由层 - 批量删除 src/app/api/files/batch-delete/route.ts 1 POST 批量删除
路由层 - 管理页 src/app/(dashboard)/admin/files/page.tsx 1 Server Component调用 data-access 渲染 AdminFilesView
模块层 - data-access src/modules/files/data-access.ts 1305 行) 11 个函数 + mapRow
模块层 - types src/modules/files/types.ts 163 行) 7 个接口/类型
模块层 - 组件 src/modules/files/components/ 6 文件 FileUpload / FileList / FilePreview / FilePreviewDialog / FileIcon / AdminFilesView
i18n messages/{en,zh-CN}/files.json 2 仅 2 个键title、description
Schema src/shared/db/schema.ts §12 - file_attachments 表 + 3 个索引
权限点 src/shared/types/permissions.ts - FILE_UPLOAD / FILE_READ / FILE_DELETE

1.2 数据流

浏览器 (AdminFilesView/FileUpload/AvatarUpload)
   │  fetch /api/upload (POST FormData)
   │  fetch /api/files/[id] (DELETE)
   │  fetch /api/files/batch-delete (POST JSON)
   ▼
API 路由层requireAuth / requirePermission
   │  直接调用 files/data-access 函数
   ▼
files/data-access.ts → shared/db → file_attachments 表
   │  存储抽象:/api/upload 与 /api/files/[id] 直接用 fs/promises
   │            /api/files/batch-delete 用 storageProvider

1.3 架构图记录情况

004_architecture_impact_map.md §2.17 与 005_architecture_data.jsonmodules.files 节点对 data-access 的导出函数签名、依赖关系记录基本完整。但发现以下遗漏(详见 §五):

  • getFileByUrl 函数未在 005 JSON 的 dataAccess 列表中记录(实际代码存在,被 settings/actions-avatar.ts 使用)。
  • 被依赖方遗漏 settings 模块004 §2.17 仅记录 app/api/upload / app/api/files/[id] / app/api/files/batch-delete / homework,遗漏 settings/actions-avatar.ts 通过 getFileByUrl + deleteFileAttachment 调用清理头像文件。
  • FilePreviewDialog 组件未在 005 JSON 的 components 列表中记录

二、现存问题与原因分析

2.1 三层架构违反:缺少 actions.ts 编排层P0

位置 问题 违反规则
src/modules/files/ 目录 actions.ts 文件 "每个模块标准结构:actions.ts(编排层)"
src/app/api/upload/route.ts L13 import { createFileAttachment } from "@/modules/files/data-access" "app/ 只能调用 modules/ 的 Server Actions 和 data-access" — API 路由虽可直调 data-access但项目规范要求所有写操作通过 actions 编排
src/app/api/files/batch-delete/route.ts L6-9 直接 import 两个 data-access 函数 同上
src/app/(dashboard)/admin/files/page.tsx L7-10 page.tsx 直接调用 data-access 函数 同上(应通过 actions 编排权限与数据获取)

原因:模块创建时未遵循标准结构,所有数据访问被路由层与页面层直接调用,跳过 actions 编排层。

后果

  1. 权限校验分散在路由层,无法集中管理;
  2. 无法在 actions 层统一埋点、审计日志、缓存策略;
  3. 与项目其他模块(如 announcements、settings、grades 等)的 actions.ts 模式不一致,破坏一致性;
  4. 无法被其他模块以 actions 形式复用settings 模块只能 import data-access

2.2 i18n 严重缺失UI 文本全部硬编码英文P0

位置 问题 违反规则
messages/en/files.jsonmessages/zh-CN/files.json titledescription 2 个键 "所有用户可见文本必须适配 i18n"
components/file-upload.tsx L48-51、L188-191、L218、L230 "File is empty" / "Click to upload or drag and drop" / "Uploaded" 等硬编码 同上
components/file-list.tsx L27-28、L37、L40、L84、L104、L117 "No files" / "File deleted" / "Download" / "Delete" 等硬编码 同上
components/file-preview.tsx L71、L113-119、L207、L215 "Download" / "Office file preview not available" / "Load preview" 等硬编码 同上
components/file-preview-dialog.tsx L29、L47 "Preview" / "File preview ·" 硬编码 同上
components/admin-files-view.tsx L33-45、L121、L135-139、L147、L154、L177、L199、L217、L261、L271 TYPE_OPTIONS 标签 + "Files"/"Total Files"/"Total Size"/"Filter by type"/"Search by file name..."/"Delete Selected"/"Deleting..." 等几十处硬编码 同上

原因组件开发时直接用英文字面量未提取翻译键i18n 文件仅 placeholder。

后果

  1. 中文用户看到全英文界面(与系统其他模块本地化不一致);
  2. 切换语言无效;
  3. 翻译协作无法进行;
  4. 违反项目硬约束。

2.3 权限校验缺失:上传路由仅 requireAuth 未走 requirePermissionP0

位置 问题 违反规则
src/app/api/upload/route.ts L31 const ctx = await requireAuth() "所有 Server Action 必须调用 requirePermission() 进行权限校验"
同文件 L18-24 已定义 FILE_UPLOAD 权限点permissions.ts L123但路由层未使用 同上

原因:上传路由创建时仅考虑登录态校验,未将 FILE_UPLOAD 权限点接入;项目已定义该权限点但未消费。

后果

  1. 任何登录用户(含无上传权限的角色)均可调用上传接口;
  2. 与 RBAC 设计意图相悖;
  3. FILE_UPLOAD 权限点形同虚设。

2.4 横向越权GET /api/files/[id] 仅 requireAuthP0

位置 问题 违反规则
src/app/api/files/[id]/route.ts L24 await requireAuth() 后直接返回任意 id 的文件元数据 "Server Action 二次校验" + 数据级别权限过滤要求
同文件 L52-58 DELETE 仅校验 FILE_DELETE,未校验调用者是否拥有该文件 同上

原因GET 路由未做权限分级DELETE 未做所有权或所属 target 关联校验。

后果

  1. 学生可通过枚举 ID 拉取他人上传的考试附件元数据(含 mimeType、url、uploaderId 等);
  2. 通过返回的 url 即可访问文件本体(文件存储在 /public/uploads/...,无签名机制);
  3. 任何 FILE_DELETE 权限者可删除他人上传的文件;
  4. 安全风险:违反 FERPA/GDPR 学生数据保护原则

2.5 缺少 loading.tsx 和 error.tsxP1

位置 问题 违反规则
src/app/(dashboard)/admin/files/ page.tsx,缺 loading.tsx / error.tsx "All student routes must include loading.tsx and error.tsx for error boundaries"admin 同样遵循,参考 admin/users、admin/roles

原因:路由未补齐标准文件。

后果

  1. 无骨架屏 → 用户首次进入白屏时间长;
  2. data-access 抛错 → 整个 dashboard 布局错误(无 error boundary 隔离)。

2.6 类型安全API 路由存在 as 断言P1

位置 问题 违反规则
src/app/api/upload/route.ts L100-102 targetType: isTargetType(...) ? (targetType as string) : null "禁止 as 断言(除类型收窄外)"
src/app/api/files/batch-delete/route.ts L23 const body = (await req.json().catch(() => null)) as { ids?: unknown } | null 同上
src/app/api/files/batch-delete/route.ts L23 body!.ids 非空断言 "可选链后禁止跟非空断言 !"(同类违规)

原因:缺少 Zod schema 校验,只能用 as 转换未验证输入。

后果类型不安全的输入直接进入业务逻辑运行时仍可能爆炸tsc 严格模式被绕过。

2.7 缺少 Zod schema 验证P1

位置 问题 违反规则
src/modules/files/ schema.ts "模块标准结构:schema.tsZod 验证)"
src/app/api/upload/route.ts L44-47 formData.get("file") / formData.get("targetType") 未做 Zod 校验 "输入使用 Zod 验证,验证失败返回结构化错误"
src/app/api/files/batch-delete/route.ts L22 body.ids 仅做 Array.isArray + typeof === "string" 简单过滤,无长度上限/格式约束 同上

原因:路由层手写最小校验,未引入 Zod schema。

后果

  1. 大量恶意 ids 可导致 inArray 查询超长 SQL
  2. targetType 可注入任意字符串进入 DB
  3. 与项目其他模块(如 announcements、classes的 schema.ts 模式不一致。

2.8 存储抽象使用不一致P1

位置 问题
src/app/api/upload/route.ts L3-4、L80-85 直接 import { mkdir, writeFile } from "fs/promises" + path.join(process.cwd(), "public", ...) 写文件
src/app/api/files/[id]/route.ts L2-3、L61-66 直接 import { unlink } from "fs/promises" 删文件
src/app/api/files/batch-delete/route.ts L5、L37 使用 storageProvider.delete() 抽象
src/modules/settings/actions-avatar.ts L2-3、L27-34 又一次直接 import { unlink } from "fs/promises"

原因storageProvider 抽象存在但只在批量删除处使用,单文件上传/删除路径未迁移。

后果

  1. 切换到 OSS/S3 时需要修改 3 处代码;
  2. 4 个调用点对路径解析逻辑重复实现DRY 违反);
  3. actions-avatar.ts 中的 path.join(process.cwd(), "public", fileRecord.storagePath) 与 storageProvider 的 delete() 行为重复,且未处理 storagePath/ 开头的情况。

2.9 FileList 组件死代码P2

位置 问题
src/modules/files/components/file-list.tsx125 行) 全代码库无任何文件 import 该组件grep from "@/modules/files/components/file-list" 为 0 结果admin-files-view.tsx 自行实现列表,未使用 FileList

原因早期创建后未接入AdminFilesView 复刻了类似 UI。

后果

  1. 死代码维护负担;
  2. 误导后续维护者以为有消费者;
  3. 125 行无测试覆盖。

2.10 缺少自定义 hooksP1

位置 问题 违反规则
src/modules/files/ hooks/ 目录 "模块标准结构:hooks/(可选)" + "逻辑复用一律抽取为自定义 hooks"
components/file-upload.tsx L43-159 上传逻辑XHR + 进度 + 状态机)全部内联在组件中 "逻辑复用一律抽取为自定义 hooks"
components/file-preview.tsx L180-233 TextPreview 内部 load 逻辑fetch + 错误处理)内联 同上
components/admin-files-view.tsx L49-128 客户端筛选、批量选择、批量删除逻辑全部内联 同上

原因:未抽取 useFileUpload / useFilePreview / useFileBatchOperations 等 hooks。

后果

  1. 组件无法独立测试;
  2. 逻辑无法在多个组件间复用(如 FileUpload 的进度逻辑无法被 AvatarUpload 复用);
  3. 单组件行数膨胀风险。

2.11 缺少 React Error Boundary 和 Suspense 骨架屏P1

位置 问题 违反规则
src/app/(dashboard)/admin/files/page.tsx 整页同步 await无 Suspense 包裹 "异步数据使用 React Suspense + 骨架屏"
components/admin-files-view.tsx 上传/批量删除错误仅 toast无 Error Boundary 隔离失败区块 "每个独立的数据区块必须用 React Error Boundary 包裹"
components/file-preview.tsx L188-198 TextPreview 的 fetch 错误仅展示文本,无重试按钮 "明确处理空数据、无权限、网络异常等边界状态"

原因:未引入 React 19 的 Error Boundary 与 Suspense 流式渲染模式。

后果

  1. 上传失败仅 toast用户无法定位失败任务重试
  2. 整页 await 阻塞流式渲染;
  3. 网络异常时整页空白。

2.12 数据级别权限过滤缺失P1

位置 问题 违反规则
src/modules/files/data-access.ts L128-143 getAllFileAttachments 不带 scope/uploaderId 过滤,返回全局数据 "所有敏感数据查询必须在 data-access 层结合当前用户权限过滤"
src/modules/files/data-access.ts L83-103 getFileAttachmentsByTarget 不校验调用者是否有权访问该 target 资源 同上
src/modules/files/data-access.ts L196-234 getFileAttachmentsWithFilters 不带任何权限维度 同上
src/app/(dashboard)/admin/files/page.tsx L25-28 仅校验 FILE_READ 权限,未结合 scope如教师只能看自己班级的文件 同上

原因:模块未引入 DataScope 概念grades/classes 模块已实现)。

后果FILE_READ 持有者可读全部文件元数据,与 K12 多角色数据隔离要求不符。

2.13 架构图遗漏getFileByUrl 未记录P2

位置 问题 违反规则
docs/architecture/005_architecture_data.json modules.files.exports.dataAccess 列出 10 个函数,但代码中实际有 11 个(缺 getFileByUrl "如果架构图未覆盖该模块的任何部分,必须优先补全架构图"

原因getFileByUrl 在 P2-13 修复时新增,未同步到 JSON。

后果AI 友好数据不准确,自动化审计会遗漏该函数的依赖分析。

2.14 架构图遗漏settings 模块依赖未记录P2

位置 问题
docs/architecture/004_architecture_impact_map.md §2.17 被依赖 仅列 app/api/upload / app/api/files/[id] / app/api/files/batch-delete / homework,遗漏 settings/actions-avatar.ts 调用 getFileByUrl + deleteFileAttachment

原因avatar 清理功能上线时未同步架构图。

2.15 avatar-upload.tsx 使用 "user_avatar" 非枚举 targetTypeP1

位置 问题 违反规则
src/modules/settings/components/avatar-upload.tsx L78 formData.append("targetType", "user_avatar") "TypeScript 严格模式:禁止 any"(类型不一致)
src/modules/files/types.ts L2 FileTargetType = "exam" | "textbook" | "question" | "announcement" | "homework" 不含 "user_avatar" 类型契约违反
src/app/api/upload/route.ts L100-102 isTargetType(...) 返回 false 后 fallback 到 null导致头像文件 targetType=null 数据完整性受损

原因:头像上传复用 /api/upload,但用了未注册的 targetType 字符串。

后果

  1. 头像文件在 DB 中 targetType 字段为 null无法按类型筛选头像
  2. 清理孤立头像文件时无法用 getFileAttachmentsByTarget("user_avatar", ...)
  3. 类型系统未保护跨模块字符串。

2.16 客户端二次筛选与硬编码 limit 200P2

位置 问题
src/app/(dashboard)/admin/files/page.tsx L26 getFileAttachmentsWithFilters({ limit: 200 }) 硬编码 200无分页
components/admin-files-view.tsx L54-75 客户端 useMemo 重复执行筛选逻辑(与 data-access 的 getFileAttachmentsWithFilters 重复)

原因:早期为简化实现,未做服务端分页 + URL 查询参数。

后果

  1. 文件数超过 200 时静默丢失;
  2. 服务端筛选与客户端筛选逻辑双写、易不一致;
  3. 无法被搜索引擎或分享链接复用筛选状态。

2.17 监控埋点缺失P2

位置 问题 违反规则
src/app/api/upload/route.tssrc/app/api/files/[id]/route.tssrc/app/api/files/batch-delete/route.ts trackEvent 调用 "方案中预留关键操作埋点接口"
src/modules/files/data-access.ts 各写函数 无审计日志(其他模块如 audit、announcements 已接入 audit-logger 同上

原因:模块创建时未规划可观测性。

后果:无法追踪上传/删除异常、容量增长、恶意批量删除等运营事件。

2.18 可访问性不足P2

位置 问题
components/file-list.tsx L70-78 <a> 链接无 aria-label,仅靠 title 提供上下文
components/file-preview.tsx L96-101 PDF iframe 缺 aria-label,仅 title
components/admin-files-view.tsx L226-229 全选 Checkbox indeterminate 状态无 ARIA 描述
components/file-upload.tsx L161-204 拖拽区 role="button" 但缺 aria-describedby 关联限制说明

三、行业差距对比

3.1 文件预览能力薄弱

  • 行业实践(如 PowerSchool、Canvas、阿里云教育Office 文档通过 Office Online Viewer / WPS 在线预览服务打开;视频支持原生 <video> 流式播放;音频支持波形 + 播放器。
  • 当前实现:仅支持 image / pdf / text 三类Office 与视频、音频统一回退到下载。
  • 影响:教师上传 PPT 课件时无法快速浏览学生作业扫描图PNG预览体验勉强可用但 Office 资料无法即时查阅。

3.2 缺少文件分类与文件夹概念

  • 行业实践:按课程/班级/学科组织文件树;支持文件夹嵌套;提供"我的文件"/"共享文件"/"班级文件"分区。
  • 当前实现:仅靠 targetType + targetId 多态关联无独立文件夹实体admin/files 是单一平铺列表。
  • 影响:教师上传大量课件后无法分类组织;学生查找特定学科资料困难。

3.3 缺少文件版本管理

  • 行业实践:同名文件覆盖时保留历史版本;支持版本对比、回滚;显示修改人/修改时间。
  • 当前实现:每次上传生成新 cuid 文件名,无版本关联;同名文件多次上传产生多个独立记录。
  • 影响:教师更新课件后旧链接失效;无法回滚误删/误改。

3.4 缺少配额与存储管理

  • 行业实践:按用户/角色/班级分配存储配额;接近上限时提醒;超限拒绝上传;管理员可查看配额使用排行。
  • 当前实现:仅全局 getFileStats 统计总量,无 per-user 配额、无超限拦截。
  • 影响单个用户可耗尽服务器磁盘K12 学校存储成本不可控。

3.5 缺少文件分享与权限管理

  • 行业实践:生成分享链接(含过期时间、密码、查看/下载权限);可按用户/班级精细授权;分享操作有审计日志。
  • 当前实现:所有文件 url 直接 /uploads/... 公开访问,无签名、无过期、无权限校验。
  • 影响严重安全风险:任何知道 URL 的人(含未登录用户)均可下载;学生隐私材料(成绩单扫描件、家长联系信息)可能泄露。

3.6 缺少病毒扫描与内容安全

  • 行业实践:上传时通过 ClamAV / 云安全服务扫描;图片通过 NSFW 检测;扫描结果记录到 DB。
  • 当前实现:仅校验 MIME 与大小,无内容安全检测。
  • 影响恶意文件可上传到服务器并被其他用户下载K12 场景下未成年人保护要求更高。

3.7 缺少图片缩略图与 CDN 加速

  • 行业实践上传图片后异步生成多档缩略图48/128/512通过 CDN 分发;列表用小图、预览用大图。
  • 当前实现:原图直出。
  • 影响:列表页加载慢;带宽浪费;移动端体验差。

3.8 缺少文件使用追踪

  • 行业实践DB 记录文件被哪些资源exam/textbook/homework引用删除文件前校验引用计数提供"孤立文件清理"任务。
  • 当前实现:仅 targetType + targetId 字段记录关联,无引用计数;删除 exam 时其附件不会自动清理。
  • 影响:磁盘孤儿文件累积;删除资源后附件残留。

3.9 多角色体验差距

  • 教师:无"我上传的"快捷筛选;无按班级/学科筛选;批量上传后无"批量设置 target"操作。
  • 学生:完全无入口查看自己上传的作业扫描图(仅 homework 模块内部使用);无法预览已上传的作业附件。
  • 家长:无入口查看学校下发的通知附件;仅靠 announcement 模块内嵌预览。
  • 管理员:无"按上传者筛选"快捷入口;无"近期 7 天"快捷时间筛选;无配额管理面板。

3.10 缺少批量操作与企业级功能

  • 行业实践:批量移动到 target、批量设置权限、批量下载ZIP 打包、批量重命名、Excel 导出文件清单。
  • 当前实现:仅批量删除。
  • 影响:管理员整理文件效率低。

四、改进优先级建议

P0必须立即修复 — 安全与架构合规)

# 改进方向
P0-1 创建 src/modules/files/actions.ts 编排层 将 upload / delete / batchDelete / query 包装为 Server ActionsrequirePermission + Zod + 审计日志),路由层改为转发到 actions
P0-2 补全 i18n 翻译键en + zh-CN files.json 提取约 40 个翻译键,组件全部接入 useTranslations("files")
P0-3 修复 /api/upload 权限校验 requireAuth() 替换为 requirePermission(Permissions.FILE_UPLOAD)
P0-4 修复横向越权 GET /api/files/[id]FILE_READDELETE /api/files/[id] 校验调用者 ownership 或拥有 FILE_DELETEdata-access 新增 assertFileOwnedBy 辅助
P0-5 文件 URL 签名保护(中长期) 改为非 public 路径 + 通过 API 路由签名分发,含过期时间与权限校验

P1本轮实施 — 质量与一致性)

# 改进方向
P1-1 新增 loading.tsx + error.tsx 骨架屏 + Error Boundary 隔离
P1-2 新增 src/modules/files/schema.ts Zod 校验 upload/batchDelete/filter 输入,移除 as 断言
P1-3 抽取 hooks useFileUpload / useFileBatchOperations / useFilePreview,组件瘦身
P1-4 统一 storageProvider 调用 upload / single delete / avatar cleanup 全部改用 storageProvider
P1-5 修复 user_avatar targetType "user_avatar" 加入 FileTargetType 枚举upload route VALID_TARGET_TYPES 同步avatar-upload.tsx 类型对齐
P1-6 引入 DataScope 过滤 data-access 的查询函数新增 scope: DataScopecurrentUserId?: string 参数,参照 grades 模块实现
P1-7 分区 Error Boundary + Suspense AdminFilesView 拆为 StatsSection / UploadSection / ListSection每区独立 Suspense + Boundary
P1-8 接入 audit-logger upload / delete / batchDelete 记录审计日志(参照 announcements 模块)
P1-9 接入 trackEvent 埋点 关键操作埋点upload_success / upload_failed / delete / batch_delete

P2中长期 — 体验与企业级)

# 改进方向
P2-1 删除 FileList 死代码 确认无消费者后删除 125 行
P2-2 同步架构图 补全 getFileByUrl 节点、FilePreviewDialog 组件、settings 依赖关系
P2-3 服务端分页 + URL 查询参数 替换硬编码 limit=200支持 ?page=&size=&type=&search=&uploader=
P2-4 a11y 增强 给所有链接/iframe/Checkbox 加 ARIA 标签;拖拽区 aria-describedby
P2-5 文件预览扩展(中长期) 接入 Office Online Viewer / 视频原生 <video> / 音频播放器
P2-6 文件版本管理(中长期) 新增 file_versions 表,同名覆盖时保留历史
P2-7 文件配额(中长期) 新增 user_storage_quota 配置data-access 校验超限admin 配额面板
P2-8 文件分享与签名 URL中长期 文件改为非 public 存储 + 签名分发;分享链接生成/吊销
P2-9 病毒扫描(中长期) 接入 ClamAV 或云扫描服务;扫描结果记录到 DB
P2-10 图片缩略图 + CDN中长期 异步生成多档缩略图CDN 分发
P2-11 引用计数与孤立文件清理(中长期) 删除资源时级联清理附件;定期清理孤儿文件任务
P2-12 文件夹/分类实体(中长期) 新增 folders 表;支持嵌套与按班级/学科组织
P2-13 批量操作扩展(中长期) 批量下载 ZIP、批量移动 target、Excel 导出清单

重构设计原则遵循说明

原则 落地方式
完全解耦 data-access 仅暴露纯函数actions 注入权限/审计;组件通过 props 接收数据(无直接 data-access import
组合优先 AdminFilesView 拆为 <StatsSection /> + <UploadSection /> + <ListSection /> 组合;逻辑全入 hooks
国际化就绪 所有可见文本走 useTranslations("files.*");提供翻译文件结构示例
最大化复用 useFileUpload hook 同时被 FileUpload 与 AvatarUpload 复用;FileIcon 已是复用单元
错误与边界处理 每区独立 Error BoundarySuspense + 骨架屏;上传任务列表保留失败项供重试
可测试性 hooks 独立可测data-access 纯函数schema 可独立测试
可扩展性 通过 FILES_ROLE_CONFIG 决定各角色可见 Widget新增角色仅改配置
企业级补充 a11y ARIA 标签、流式 RSC、storageProvider 二次校验、audit-logger + trackEvent

五、架构图同步说明

5.1 004_architecture_impact_map.md §2.17 同步项

  1. 导出函数章节:
    • 补充 getFileByUrl 函数(用于头像 URL 反查文件记录)
    • 修正 getFileAttachmentsByOwner → 实际函数名为 getFileAttachmentsByUploader
    • 补充 FilePreviewDialog 组件到组件清单
  2. 依赖关系章节:
    • 被依赖方新增 settingsactions-avatar.ts 调用 getFileByUrl + deleteFileAttachment
  3. 已知问题章节:
    • 移除 "⚠️ P2无 actions.ts" 标记(本轮 P0-1 实施后失效)
    • 新增 "i18n 缺失"、"权限校验缺失"、"横向越权"标记(实施后转为

5.2 005_architecture_data.json 同步项

  1. modules.files.exports.dataAccess 数组补充:
    {
      "name": "getFileByUrl",
      "signature": "(url: string) => Promise<FileAttachment | null>",
      "file": "data-access.ts",
      "purpose": "按 URL 反查文件附件记录(用于头像等场景的旧文件清理)",
      "deps": ["shared.db", "shared.db.schema.fileAttachments"],
      "usedBy": ["settings/actions-avatar.ts"]
    }
    
  2. modules.files.exports.actions 节点新增P0-1 实施后):
    • uploadFileAction / deleteFileAction / batchDeleteFilesAction / getFileListAction / getFileStatsAction
  3. modules.files.exports.components 数组补充 FilePreviewDialog
  4. modules.files.dependencies.usedBy 数组新增 "settings"
  5. modules.files.typesFileTargetType 定义更新为 "exam" | "textbook" | "question" | "announcement" | "homework" | "user_avatar"P1-5 实施后)

六、翻译文件结构示例i18n 就绪)

messages/en/files.jsonmessages/zh-CN/files.json 建议结构:

{
  "title": "File Management",
  "description": "View and manage all uploaded files in the system.",
  "nav": { "files": "Files" },
  "upload": {
    "title": "Click to upload or drag and drop",
    "hint": "Images, PDF, Word, Excel, PPT, Text, ZIP / RAR · up to {size}",
    "success": "{name} uploaded",
    "error": "{name}: {message}",
    "empty": "File is empty",
    "tooLarge": "File size exceeds {limit} limit",
    "invalidType": "File type {type} is not allowed",
    "uploaded": "Uploaded",
    "remove": "Remove",
    "networkError": "Network error",
    "invalidResponse": "Invalid response"
  },
  "list": {
    "empty": "No files",
    "emptyDescription": "There are no files yet.",
    "download": "Download",
    "delete": "Delete",
    "deleted": "File deleted",
    "deleteFailed": "Failed to delete file"
  },
  "preview": {
    "trigger": "Preview",
    "title": "File preview",
    "download": "Download",
    "zoomIn": "Zoom in",
    "zoomOut": "Zoom out",
    "office": {
      "title": "Office file preview not available",
      "hint": "Download the file to view its contents in your Office application."
    },
    "other": {
      "title": "Preview not available",
      "hint": "Download the file to view its contents."
    },
    "text": {
      "title": "Text file",
      "hint": "Click below to load the content.",
      "load": "Load preview",
      "loading": "Loading...",
      "error": "Failed to load text: {message}"
    }
  },
  "admin": {
    "title": "Files",
    "subtitle": "Upload and manage all files in the system.",
    "stats": {
      "totalFiles": "Total Files",
      "totalSize": "Total Size"
    },
    "filter": {
      "byType": "Filter by type",
      "search": "Search by file name...",
      "allTypes": "All Types",
      "images": "Images",
      "pdf": "PDF",
      "word": "Word",
      "wordDocx": "Word (docx)",
      "excel": "Excel",
      "excelXlsx": "Excel (xlsx)",
      "powerpoint": "PowerPoint",
      "powerpointPptx": "PowerPoint (pptx)",
      "text": "Text",
      "zip": "ZIP"
    },
    "selection": {
      "selected": "{count} selected",
      "deleteSelected": "Delete Selected",
      "deleting": "Deleting...",
      "deleted": "Deleted {count} file(s)",
      "deleteFailed": "Failed to delete files"
    },
    "empty": {
      "title": "No files found",
      "description": "Try adjusting your filters or upload a new file."
    },
    "columns": {
      "file": "File",
      "size": "Size",
      "type": "Type",
      "uploaded": "Uploaded",
      "actions": "Actions"
    }
  }
}

本报告由资深全栈架构师基于 2026-06-25 代码状态生成,所有 P0/P1 项将在本会话内完成实施P2 中长期项按优先级逐步推进。