项目:interview-platform | 版本:v1.2 | 生成日期:2026-10-06 | 依据:源码分析
依赖清单是工程性格最诚实的体检报告:为哪些能力付费、刻意不为什么能力付费,都比任何宣言更真实。interview-platform 的 package.json(仓库根目录)共声明 36 个 dependencies 与 22 个 devDependencies,配合 packageManager: "pnpm@10.34.5" 的精确锁定与 .npmrc 的 registry=https://registry.npmmirror.com/ 镜像源,构成一个体量克制、边界清晰的依赖宇宙。从这份清单能直接读出四条策略。其一,框架家族精确锁版本:next 16.2.7、next-auth 4.24.14、react 19.2.4、react-dom 19.2.4、eslint-config-next 16.2.7 五个包不带插入符(无 ^ 前缀),这是刻意的——Next.js 大版本间的破坏性变更(如 16 把 middleware 更名 proxy、params 变 Promise,见《14-配置与环境详解》第 3 节)足以证明对框架家族做精确锁定是值得的。其二,运行时依赖几乎全部是「能力件」:除框架外,每个依赖都对应一个明确的能力域(判题编辑器、Markdown 渲染、语音、邮件、OSS),没有引入状态管理库、UI 组件库、工具函数集之类的「全家桶」。其三,AI 域零依赖:整个 AI 能力没有使用任何 SDK(没有 openai、没有 Vercel AI SDK、没有 langchain),全部靠原生 fetch 与自写的 116 行 src/lib/deepseek.ts 实现——这条决策的完整考古见《16-决策记录ADR》ADR-004,本篇从依赖角度给出它的另一面账本。其四,devDependencies 里的两个「幽灵」:@playwright/test 已安装但仓库内无任何用例(《09-测试与质量保障》第 6 节),@types/node 锁在 ^20 而运行时是 Node 22——两者都是可以立即收敛的小额债务。
版本号的读取口径需要先说明:下文所有版本号逐一摘自 package.json 当前快照(2026-10-06 分析时点);实际安装版本以 pnpm-lock.yaml 为准,^ 范围内的锁文件固定意味着「依赖不会悄悄漂移,但升级需要主动提交锁文件变更」(CI 的 --frozen-lockfile 与 Docker 同参数安装都会拒绝漂移,《14-配置与环境详解》第 6 节的第四条铁律)。依赖更新由 .github/dependabot.yml 每周各开一批 npm 与 github-actions 升级 PR,这是当前唯一的依赖巡检机制。
| 依赖 | 版本 | 用途 | 使用位置(节选) | 选型理由与替代方案 | 升级风险 |
|---|---|---|---|---|---|
| next | 16.2.7(精确锁) | 全栈框架:页面 + API + 构建 | 全仓 | App Router 生态唯一选择;替代仅 Remix/SvelteKit 级别的重写 | 大版本破坏性变更多(middleware→proxy、Promise params);锁版本是对的 |
| react / react-dom | 19.2.4(精确锁) | UI 运行时 | 全部客户端组件 | 与 Next 16 配套;替代无从谈起 | 跟随 Next 同步升级,不可单独动 |
| next-auth | 4.24.14(精确锁) | 认证(Credentials + JWT 会话) | src/lib/auth.ts、src/proxy.ts、permission.ts | v4 稳定且资料多;替代 Auth.js v5(迁移成本高)或自研(风险高) | v4→v5 是 API 全变的大迁移;v4 维护窗口需关注 |
| prisma | ^7.8.0 | ORM CLI(迁移/seed/studio) | prisma.config.ts、Dockerfile CMD | 类型安全 + 迁移体系成熟;替代 Drizzle/Kysely 需重写全部查询 | 7.x 新架构,minor 升级需回归迁移链 |
| @prisma/client | ^7.8.0 | Prisma 运行时客户端 | src/generated/prisma/ 生成物、各查询点 | 与 CLI 同版本联动 | 必须与 prisma CLI 同步升 |
| @prisma/adapter-pg | ^7.8.0 | 驱动适配器(pg 连接池) | src/lib/prisma.ts | Prisma 7 推荐架构,连接池自主可控 | 跟随 prisma 主版本 |
| pg | ^8.21.0 | PostgreSQL Node 驱动 | src/lib/prisma.ts、prisma/seed.ts | 事实标准驱动;替代 postgres.js 无收益 | 极稳定,低风险 |
| zod | ^4.6.5 | 请求体声明式校验 | src/lib/schemas.ts、validate.ts 及新接口 | 社区标准;替代 yup/valibot 无必要 | 3→4 已是大版本跃迁(项目直接从 4 起步),后续 minor 低风险 |
| swr | ^2.4.1 | 客户端数据获取缓存 | src/lib/swr.ts + 全部只读页面 | 轻量、去重/重试开箱即用;替代 TanStack Query 需改全部页面 | 低风险 |
| jose | ^6.2.3 | JWT 签发/校验(后台 Bearer) | src/lib/jwt.ts | Edge 兼容、零依赖纯 Web Crypto;替代 jsonwebtoken(不兼容 Edge) | 低风险 |
| bcryptjs | ^3.0.3 | 密码加盐哈希 | src/lib/auth.ts、注册路由 | 纯 JS 免原生编译(Docker 友好);替代 bcrypt 原生版性能更好但需 node-gyp | 低风险;轮数 10 由测试锁定 |
| nodemailer | ^9.0.5 | SMTP 发信(注册验证码) | src/lib/mailer.ts | 事实标准;替代邮件 API 服务商 SDK 需换服务商 | 低风险 |
| ali-oss | ^6.23.0 | OSS 上传 + STS assumeRole | src/lib/oss.ts、oss-upload.ts;next.config.ts serverExternalPackages | 阿里云官方 SDK;替代 web-direct 已废弃 | 纯 Node SDK 被 Turbopack 排除打包,升级需确认 serverExternalPackages 仍必要 |
| ws | ^8.21.3 | 服务端 WebSocket 客户端(ASR 代理) | src/app/api/voice/asr/route.ts | 唯一需要 Node 侧 WS 的场景(豆包二进制协议) | 低风险 |
| @volcengine/rtc | ^4.69.0 | RTC Web SDK(视频面试进房) | src/components/VideoInterviewView.tsx(唯一使用点) | 火山官方 Web SDK,与 SeedRealtime 配套 | 跟随火山侧版本节奏;Token/OpenAPI 协议为自维护代码,SDK 升级需回归 |
| react-markdown | ^10.1.0 | Markdown 渲染 | MarkdownRenderer.tsx、MarkdownRendererInner.tsx | remark/rehype 管道可插拔,sanitize 无缝;替代 marked+DOMPurify 需自管安全 | 配合 unified 生态升级,major 变更偶有 |
| remark-gfm | ^4.0.1 | GFM 扩展(表格/任务列表) | 同上 | 题解渲染需要表格支持 | 跟随 unified 生态 |
| rehype-highlight | ^7.0.2 | 代码块高亮 | 同上 | 与 highlight.js 联动 | 低风险 |
| rehype-sanitize | ^6.0.0 | Markdown 消毒(XSS 防线) | 同上 | 全站 AI 输出/题面的安全闸门(《08-安全与权限设计》第 8 节) | 不可轻易移除或降级;schema 定制需谨慎 |
| highlight.js | ^11.11.1 | 语法高亮引擎 | rehype-highlight 底层 | 成熟稳定 | 低风险 |
| mermaid | ^11.15.0 | 题解内图表渲染 | MermaidRenderer.tsx、MarkdownRendererInner.tsx | 图表能力唯一选择;体积数 MB 级 | 体积大头(见第 5 节健康度);建议未来动态 import |
| recharts | ^3.8.1 | 雷达/折线/饼图 | src/components/charts/*、admin dashboard | React 生态图表主流;替代 echarts 更重 | v3 为新大版本,minor 低风险 |
| codemirror | ^6.0.2 | CodeMirror 6 门面包(basicSetup/EditorView) | CodeMirrorEditor.tsx | 模块化编辑器,按需装配语言 | 低风险 |
| @codemirror/state | ^6.6.0 | 编辑器状态核心 | 同上 | CM6 分包架构必需 | 随 CM6 家族同步 |
| @codemirror/view | ^6.43.0 | 编辑器视图层 | 同上 | 同上 | 同上 |
| @codemirror/language | ^6.12.3 | 语言支持基座 | 同上 | 同上 | 同上 |
| @codemirror/lang-javascript | ^6.2.5 | JS/TS 语言包 | CodeMirrorEditor.tsx(显式 import) | 对应判题语言 JS/TS | 低风险 |
| @codemirror/lang-python | ^6.2.1 | Python 语言包 | 同上(按语言装配) | 对应判题语言 | 低风险 |
| @codemirror/lang-java | ^6.0.2 | Java 语言包 | 同上 | 对应判题语言(注意包装器局限) | 低风险 |
| @codemirror/lang-cpp | ^6.0.3 | C++ 语言包 | 同上 | 对应判题语言 | 低风险 |
| @codemirror/lang-sql | ^6.10.0 | SQL 语言包 | 同上 | 数据库类题目的编辑体验 | 低风险 |
| react-easy-crop | ^5.5.7 | 头像裁剪 | AvatarCropper.tsx | 轻量专一;替代 react-image-crop 同级 | 低风险 |
| lucide-react | ^1.17.0 | 图标库 | TopNav、admin 各页、settings 等 | Tree-shakeable 单文件组件 | 低风险 |
| clsx | ^2.1.1 | 类名拼接 | src/lib/utils.ts 的 cn() | 2KB 级工具 | 零风险 |
| dotenv | ^18.0.3 | .env 加载(Prisma CLI) | prisma.config.ts 第一行 | Prisma 7 新架构的配套 | 仅影响 CLI 侧 |
表中值得驻足的一行是 react-markdown 全家桶(react-markdown + remark-gfm + rehype-highlight + rehype-sanitize + highlight.js + mermaid):这六个包组成的是一条完整的不可信内容渲染管道——题面、题解、AI 输出全部经它渲染,其中 rehype-sanitize 是 XSS 的真实闸门(CSP 尚处 Report-Only 观察期,《08-安全与权限设计》第 8 节)。这条管道的依赖之间是 unified 生态的版本耦合关系,升级任何一环都要整组回归「题目详情页渲染 + AI 反馈渲染 + Mermaid 图」三个场景。
| 依赖 | 版本 | 用途 | 使用位置 | 备注 |
|---|---|---|---|---|
| typescript | ^5 | 类型系统 | 全仓 | strict 全开;tsconfig.test.json 分离测试类型 |
| eslint | ^9 | 静态检查 | eslint.config.mjs | flat config,三条豁免规则带理由注释 |
| eslint-config-next | 16.2.7(精确锁) | Next 官方规则集 | 同上 | 与 next 版本联动锁死 |
| vitest | ^4.1.8 | 单测框架 | vitest.config.ts | jsdom + globals: true |
| @vitest/coverage-v8 | ^4.1.8 | 覆盖率 | 同上 | 门槛锁 src/lib/** 40%/30% |
| @testing-library/react | ^16.3.2 | UI 测试 | 4 个组件测试 | — |
| @testing-library/jest-dom | ^6.9.1 | DOM 断言匹配器 | src/test/setup.ts | — |
| @testing-library/user-event | ^14.6.1 | 交互模拟 | 组件测试 | — |
| jsdom | ^29.1.1 | 测试 DOM 环境 | vitest 配置 | — |
| @playwright/test | ^1.61.0 | E2E(未使用) | 无(无 config 与用例) | 幽灵依赖,见第 6 节健康度 |
| tailwindcss | ^4 | 原子化样式(编译期) | postcss.config.mjs | v4 编译期形态故列 devDep 是正确的 |
| @tailwindcss/postcss | ^4 | Tailwind v4 的 PostCSS 插件 | 同上 | 与 tailwindcss 同步 |
| husky | ^9.1.7 | git hooks | prepare 脚本、.husky/pre-commit | — |
| lint-staged | ^17.5.1 | 暂存区 lint | package.json 内配置 | 对 ts/tsx/js/mjs 执行 eslint --fix |
| tsx | ^4.22.4 | TS 脚本直跑 | prisma.config.ts 的 seed 命令 | Prisma 7 的 seed 新写法 |
| @types/node | ^20 | Node 类型 | 全仓 | 与 Node 22 运行时不齐(见第 6 节) |
| @types/pg | ^8.20.0 | pg 类型 | prisma.ts 等 | — |
| @types/nodemailer | ^8.0.1 | nodemailer 类型 | mailer.ts | 与 nodemailer 9 的类型版本号错位属常规 |
| @types/ws | ^8.18.1 | ws 类型 | asr 路由 | — |
| @types/ali-oss | ^6.23.3 | ali-oss 类型 | oss.ts | — |
| @types/react | ^19 | React 类型 | 全仓 | — |
| @types/react-dom | ^19 | React DOM 类型 | 全仓 | — |
devDependencies 的结构同样体现克制:没有 prettier(格式化交给 eslint 与编辑器约定)、没有 commitlint(约定式提交靠 AGENTS.md 约定第 6 条自律)、没有独立的 mock 库(vitest 内置 vi.mock 够用)。tailwindcss 出现在 devDependencies 而非 dependencies,是 Tailwind v4「编译期框架」形态的正确写法——样式在构建时编译进 CSS 产物,运行时零依赖。
用途与使用面:next-auth 是本项目认证的唯一支柱,使用面集中在三个文件——src/lib/auth.ts(authOptions:CredentialsProvider、JWT 策略、jwt/session 双回调、pages.signIn: "/login")、src/proxy.ts(next-auth/jwt 的 Edge 兼容导出 getToken 做页面门禁)、src/lib/permission.ts(getServerSession 通道之一)。src/app/api/auth/[...nextauth]/route.ts 挂载 handler,src/lib/auth.ts 另导出 auth() 包装 getServerSession(authOptions)——源码注释特意说明 NextAuth v4 的 handler 没有 .auth 属性(那是 v5 API),这个包装是防止后续维护者按 v5 习惯调用时踩 TypeError。
选型理由:项目只需要「邮箱 + 密码 + 验证码」的自建体系,next-auth 提供的会话管理(JWT 签发、cookie 处理、csrf 防护、/api/auth/* 全套路由)是现成的;备选的自研方案要重新踩一遍 cookie 属性、CSRF 与密钥管理的坑,收益不成比例。v4 而非 v5 的动机推断是:v5(Auth.js)当时对 Next 16 的适配与资料成熟度不如 v4,且 v5 的 auth() 惯例反而容易与本项目的自定义包装混淆 ⚠️ 待确认(仓库内无选型讨论文档)。
升级风险与锁版本的理由:v4→v5 是一次 API 全变的大迁移——providers 声明、callbacks 签名、middleware 集成方式全部重写,且本项目在 jwt/session 回调里叠了自定义逻辑(token.id/role/image 注入、session 回调每次回查用户并按 banned 拒签),迁移时这些行为必须逐条等价复刻(封禁即时失效是安全语义,不容 regression)。4.24.14 精确锁版本是把「何时迁移」的决定权留在手里:dependabot 的 PR 对该包应保持永不自动合并。相关风险(AUTH_SECRET 三处一致性、session 回查的性能代价)分别见《08-安全与权限设计》第 2 节与《10-性能设计与优化》第 6 节建议 7。
分工结构:Prisma 7 在本项目拆成四个包协作——prisma(CLI:migrate dev/deploy、studio、generate,由 prisma.config.ts 驱动,seed 命令配置为 tsx prisma/seed.ts)、@prisma/client(运行时客户端,代码生成到 src/generated/prisma/ 并被 .gitignore 排除)、@prisma/adapter-pg(驱动适配器,把查询下推给 pg 驱动)、pg(真正的 PostgreSQL 连接池)。src/lib/prisma.ts 的 24 行把它们串成单例:new Pool({ connectionString }) → new PrismaPg(pool) → new PrismaClient({ adapter }),非生产环境挂 globalThis。prisma/seed.ts 复用同一组合(自带 Pool + PrismaPg + PrismaClient),说明 seed 与应用运行时共享同一套连接形态。
选型理由与代价:Prisma 的核心竞争力在本项目的兑现方式是「43 个模型的类型安全直达调用点 + 迁移体系」(22 个迁移目录构成演进史,见《16-决策记录ADR》ADR-005/006);备选 Drizzle 更轻但迁移与关系建模生态弱、Kysely 是纯查询构建器需自管 schema 演进。代价集中于 Prisma 7 的新架构:生成物必须手动 generate(无 postinstall,《12-FAQ与故障排查》第 2 条)、CLI 只读 .env(与 Next 的 .env.local 优先级形成双加载器分裂,《12-FAQ与故障排查》第 1 条)、package.json 的 prisma.seed 旧写法废弃。
升级风险:Prisma 7 是较新的大版本,minor 升级需重点回归三处——迁移链的可重放性(生产容器 CMD 每次 migrate deploy)、驱动适配器的连接参数透传(当前 Pool 未显式配 max,《10-性能设计与优化》第 3 节 ⚠️ 待确认)、生成物路径约定(src/generated/prisma/ 被 ESLint/tsconfig 排除逻辑引用)。pg 与 @prisma/adapter-pg 属低风险跟随升级。
渲染管道:src/components/MarkdownRenderer.tsx 与 MarkdownRendererInner.tsx(配合 MermaidRenderer.tsx)把 react-markdown 组装成全站统一的不可信内容渲染器:remark-gfm 让题解支持表格与任务列表,rehype-highlight + highlight.js 提供代码高亮,rehype-sanitize 在 DOM 化前剔除危险标签与属性。管道的安全地位使其有一个特殊约束:sanitize schema 的任何放宽都要按安全评审流程走(当前是默认 schema,未做白名单定制 ⚠️ 待确认——意味着 Mermaid 代码块能渲染说明 sanitize 配置放行了对应结构,具体放行策略在组件内实现)。选型上,react-markdown 的替代品(marked、markdown-it)都需要自行拼装 sanitize 与高亮,unified 生态的可插拔性在此场景不可替代。
前端体积三巨头:mermaid(数 MB 级,仅在题解含图时需要)、recharts(仅看板与 admin 仪表盘需要)、CodeMirror 家族(8 个包,仅代码题标签页需要)。三者目前都是常规 import,未见 dynamic import 按需加载(《10-性能设计与优化》第 5 节 ⚠️ 待确认),首包体积受此拖累——这是依赖清单里「能力正确、装配欠优化」的典型:包选得都对,但加载策略还是粗粒度的。语音相关的依赖构成另一组值得记录的事实:@volcengine/rtc(约百 KB 级 Web SDK)只在 VideoInterviewView.tsx 一个文件使用,ws 只在 ASR 代理一个路由使用——两个重特化依赖的使用面都被收敛在单文件内,替换或移除的爆炸半径很小。
综合以上盘点,给这份依赖清单做一个体检结论。健康的部分:其一,总量克制——36 个运行时依赖里没有一个是「顺手装装」的,每个都能在源码里找到明确使用点(除下述两个幽灵);其二,锁版本策略有意识(框架家族精确锁 + 其余插入符 + 锁文件冻结 + dependabot 巡检的四层结构);其三,AI/状态管理/工具函数三域的零依赖决策把供应链面压到最小——依赖越少, CVE 暴露面与升级负担越小,这个项目深谙此道;其四,重特化依赖(RTC、ws、ali-oss)的使用面收敛良好。
需要处理的部分,按优先级列出四条。第一,@playwright/test 是幽灵依赖:已声明、已随每次安装下载(Playwright 及其浏览器二进制的安装体积不小),但仓库无 config 无用例——要么按《09-测试与质量保障》第 6 节把 E2E 骨架立起来(让依赖转正),要么先移除(止损),悬置是最差状态。第二,@types/node ^20 与 Node 22 运行时不齐:CI 与 Docker 都用 22,类型却按 20 校验,node: 内建模块的新 API 类型缺失,属一行可修的错位(升到 ^22)。第三,@types/nodemailer ^8 对 nodemailer ^9 的主版本错位,编译不报错但存在类型与行为漂移的理论空间,低优先级对齐即可。第四,无自动化 CVE 扫描:dependabot 只管版本升级 PR,没有 pnpm audit 或等价物进入 CI——对 ali-oss、ws 这类持有凭证与外部数据的老牌 SDK,建议在 CI 加一条 audit 步骤(只封高危及阻断性漏洞,避免噪声)。整体评级:这份依赖清单是一份「低负载、高意图」的清单——总量约为同类全栈项目的六到七成,选型每个都有可陈述的理由(本篇即逐条陈述),债务集中且小额,不存在结构性风险;未来最大的两个依赖级事件已经可以预见:next-auth v5 迁移与 mermaid 的按需加载改造,两者都值得单独排期而非顺带处理。