Files
wlt 4cd889c081 feat: interview review module with whisper.cpp ASR + AI analysis + frontend page
New backend module 'interview-review' provides:
- Audio upload (50MB limit, MP3/M4A/WAV/AAC/OGG/MP4/WebM)
- Text transcript submission
- whisper.cpp local ASR integration (tiny + base models)
- AI analysis (4-dimension scoring: logic/expression/professionalism/stability)
- Speech analysis (filler words detection, pace, duration)
- Async processing pipeline with status polling
- Graceful fallback to mock ASR when whisper unavailable

New frontend page 'pages/review/review.vue' with 3 modes:
- List mode: review history with status indicators
- Upload mode: audio file upload or text paste
- Report mode: score radar, dimension bars, analysis details

Docs updated: PROJECT-STATUS.md v4.4, FEATURE-LIST.md v4.2, ROADMAP.md v4.2
2026-06-16 18:32:25 +08:00

11 KiB
Raw Permalink Blame History

职引 (ZhiYin) — AGENTS.md

AI 模拟面试教练,专注校招。NestJS + uni-app(Vue3) + MongoDB。


一、项目结构

zhiyin/
├── backend/                     # NestJS 10.x 后端 (端口 3006, 前缀 /api)
│   └── src/
│       ├── main.ts              # 入口:DOMMatrix polyfill → NestFactory → CORS → ValidationPipe
│       ├── app.module.ts        # 根模块:导入全部子模块 + JWT/Throttler/Mongoose
│       ├── common/
│       │   ├── guards/          # JwtAuthGuard (全局), admin.guard.ts
│       │   ├── strategies/      # JwtStrategy
│       │   ├── decorators/      # @CurrentUser, @Public()
│       │   └── filters/         # AllExceptionsFilter
│       └── modules/             # 19 个模块(详见下文)
├── zhiyin-app/                  # uni-app 3.x 前端 (H5 + 微信小程序)
│   └── src/
│       ├── pages/               # 18 个页面 (pages.json 路由)
│       ├── services/api.ts      # API 调用封装 (uni.request)
│       ├── config.ts            # 端点定义 + api() 辅助函数
│       └── App.vue              # 设计 Token + 全局样式
└── docs/                        # 产品/架构/部署/路线图文档

后端模块清单

模块 职责
user 手机/邮箱/密码/微信登录, JWT, 配额
interview AI 面试核心(多轮对话 + 评分 + 报告 + 进度)
ai AI 调用封装(deepseek-v4-flash 主 + step-3.5-flash 备)
analyze 简历诊断 / 优化 / 技能缺口分析
resume 简历 CRUD
member 会员套餐 / 权益扣减
payment 微信支付 v3Native + JSAPI + 回调)
progress 进步轨迹雷达图 / 打卡日历 / 行业基准 / 岗位匹配
contribution 面经贡献 + 公司题库(数据飞轮核心)
schedule 定时任务:VIP 过期降级、每日一题推送、微信 token 刷新
share 分享链接生成 / 访问追踪 / 积分奖励
tts 语音合成(TTS
admin 管理后台 API
positions 热门岗位维护
interview-review 面试复盘(音频上传 -> whisper.cpp ASR -> AI 评析 -> 口语分析)
upload 文件上传(PDF/图片)
email 邮件发送
daily-question 每日一题 API
schemas/ 共享 Schemapricing 定价、site-config、company-bank 等)

前端页面(3 Tab + 16 子页)

  • Tab1 面试: pages/index/index → interview → report
  • Tab2 面经: pages/history/history → contribute → company-bank
  • Tab3 我的: pages/user/user → login/member/progress/resume/review/about/agreement/privacy/admin/share
  • 其他: internship, result

二、架构约定(必须遵守)

模块模式

每个业务模块遵循 NestJS 标准结构:

模块名/
├── 模块名.module.ts    # @Module({ imports: [MongooseModule.forFeature(...)], controllers, providers, exports })
├── 模块名.controller.ts # @Controller('prefix'),注入 service
├── 模块名.service.ts    # @Injectable(),注入 Model
└── 模块名.schema.ts     # @Schema({ timestamps: true })class + SchemaFactory

认证体系

  • 全局守卫: JwtAuthGuard 默认拦截所有路由(在 app.module.tsAPP_GUARD 注册)
  • 白名单: 公开接口加 @Public() 装饰器(登录、注册、支付回调、分享访问等)
  • 管理员: 管理接口加 @UseGuards(AdminGuard)admin controller 内部)
  • 当前用户: @CurrentUser('userId') 从 JWT payload 提取用户 ID
  • JWT 过期: 7 天,在 app.module.ts 和每个模块的 JwtModule.register 中配置

安全硬性要求

  1. JWT_SECRET 必须来自环境变量,不允许任何硬编码 fallback(已有历史漏洞修复)
  2. 所有外部输入经过 class-validator ValidationPipe({ whitelist: true, forbidNonWhitelisted: true })
  3. 修改用户额度/积分使用 findOneAndUpdate + $inc 原子操作,禁止 read-modify-write
  4. 支付订单查询校验 userId 归属,防止 IDOR
  5. CORS 生产环境必须配置白名单(当前在 main.ts 中从 CORS_ORIGINS 环境变量读取)
  6. 用户内容输出到响应时避免泄漏敏感信息(验证码、密钥等)
  7. MongoDB 查询中对外部输入的字符串做特殊字符转义(尤其在 admin 模块)

AI 调用

  • 主模型: opencode-go (deepseek-v4-flash)
  • 备用模型: NVIDIA (stepfun-ai/step-3.5-flash)
  • 主用不可用时自动切换(在 ai 模块处理)
  • 环境变量: AI_PRIMARY_KEY, AI_BACKUP_KEY

支付(微信支付 v3

  • Native 支付(H5 扫码): POST /payment/create
  • JSAPI 支付(小程序内): POST /payment/jsapi
  • 支付回调: POST /payment/notify@Public,验签 + 解密 + 自动开会员)
  • 需要微信商户证书文件(通过 postbuild 复制到 dist

三、开发命令

后端

# 路径: backend/
npm run start:dev          # 开发模式(watch
npm run build              # 编译到 dist/
npm test                   # 单元测试(43 个,jest --forceExit --detectOpenHandles
npm run test:e2e           # 集成测试(11 个,需 MongoDB 运行)
npm run test:cov           # 覆盖率报告
npm run test:browser       # Playwright API 测试(需后端运行)

前端

# 路径: zhiyin-app/
npm run dev:mp-weixin      # 微信小程序开发(uni -p mp-weixin
npm run build:mp-weixin    # 构建小程序(输出 dist/build/mp-weixin/
npm run dev:h5             # H5 开发(端口 8888,带 /api 代理到 localhost:3006
npm run build:h5           # 构建 H5(输出 dist/build/h5/
npm test                   # 前端单元测试(vitest,7 个)

构建检查

# 后端构建(注意 OOM:需 NODE_OPTIONS="--max-old-space-size=2048"
cd backend && NODE_OPTIONS="--max-old-space-size=2048" npx nest build

部署

cd backend && npx nest build
cp -rf dist/* /www/wwwroot/server/zhiyin/backend/dist/
cp -r certs /www/wwwroot/server/zhiyin/backend/dist/src/certs
pm2 restart yhl-backend
sleep 3 && curl -s http://localhost:3006/api/user/wx-login -X POST -H "Content-Type: application/json" -d '{"code":"test"}'

小程序上传

cd zhiyin-app && npm run build:mp-weixin && node scripts/upload-mp.js

四、测试注意事项

  • e2e 测试需要 MongoDB 运行 + jest-setup.ts 设置测试 JWT_SECRET
  • payment.controller.spec.ts 涉及微信支付,需 mock 外部依赖
  • benchmark.service.spec.ts 涉及行业基准计算
  • Playwright 测试需要后端已在运行(测试 api.browser.spec.ts
  • 测试文件位置:backend/src/**/*.spec.ts(单元),backend/test/*.e2e-spec.ts(集成),backend/test/*.browser.spec.ts(浏览器)
  • 前端测试:zhiyin-app/src/**/*.spec.tsvitest + jsdom

五、定时任务(3 个 cron,在 schedule 模块)

服务 周期 职责
VipExpiryService 每日 00:00 扫描过期 VIP 并降级为 free 计划
DailyQuestionPushService 每日 09:00 通过微信订阅消息推送每日一题(需配置模板 ID)
WechatTokenService 每 2 小时 刷新微信 access_token(缓存到 Redis

六、项目状态与开发阶段

当前: Phase 0.5 完成,Phase 1MVP 上线)进行中

阶段 状态 关键交付
Phase 0: 战略升级 完成 定价重构(免费 + ¥19.9/月),三层壁垒设计
Phase 0.5: 壁垒构建 完成 数据飞轮(面经贡献+题库),留存入围(进步轨迹+打卡日历+每日一题)
Phase 1: MVP 上线 🚧 当前 小程序审核提交、微信登录联调、生产部署、100 人内测
Phase 1.5: 商业化 📋 规划 冲刺版 ¥49.9/月、每日一题定时推送、PMF 验证
Phase 2: 增强 + 题库 📋 规划 50+ 校招岗位、技能缺口分析、公司真题库建设
Phase 3: 秋招冲刺 📋 规划 高校合作、B 端服务、KOC 推广

详细产品规划见 docs/PRODUCT-PLAN.md,路线图见 docs/ROADMAP.md


七、环境变量

后端(backend/.env,不提交 git,在 .gitignore 中)

MONGODB_URI=mongodb://localhost:27017/zhiyin
JWT_SECRET=your-strong-secret-at-least-32-chars
PORT=3006
AI_PRIMARY_KEY=xxx
AI_BACKUP_KEY=xxx
WECHAT_APPID=wxf466b3c3bc411ffc
WECHAT_MCHID=xxx
WECHAT_API_KEY=xxx
WECHAT_SERIAL_NO=xxx
WECHAT_PRIVATE_KEY_PATH=/path/to/apiclient_key.pem
WX_DAILY_QUESTION_TMPL=微信订阅消息模板 ID
CORS_ORIGINS=http://localhost:8888,https://zhiyin.yzrcloud.cn
WHISPER_CPP_PATH=/home/wlt/whisper.cpp   # whisper.cpp 路径
WHISPER_MODEL=base                        # ASR 模型:tiny / base / small
WHISPER_LANGUAGE=zh                       # ASR 语言
WHISPER_THREADS=4                         # ASR CPU 线程数

前端(zhiyin-app/.env.production,已提交 git

VITE_API_BASE_URL=https://zhiyinwx.yzrcloud.cn/api
VITE_APP_NAME=AI磁场

八、技术细节与坑

  1. DOMMatrix polyfill: main.ts 顶部有 pdf-parse 所需的浏览器 API polyfillDOMMatrix / DOMPoint),新增 PDF 相关功能时注意兼容性
  2. postbuild: backend/package.json 中的 postbuild 脚本自动复制 certs/dist/src/certs/,这是微信支付证书的必要步骤
  3. 微信小程序 appid: zhiyin-app/manifest.jsonmp-weixin.appid = wxf466b3c3bc411ffc;开发模式 appid = __UNI__DEV__
  4. 前端 API 调用: zhiyin-app/src/services/api.ts 封装了 uni.request,自动处理 token 注入(从 uni.getStorageSync('token'))和 401 过期跳转
  5. 前端环境判断: config.ts 中使用 // #ifdef H5 / // #ifdef MP-WEIXIN 条件编译区分 H5 和小程序
  6. API 限流: 100 次/60 秒(在 app.module.ts 中配置),注意避免在定时任务和批量操作中被限
  7. 验证码: 开发模式下手机验证码固定为 123456user.service.ts 中实现),生产环境需移除
  8. MongoDB: 8 个核心集合 + 2 个分享集合

九、交付检查清单(每次实施/修改后执行)

Step 1: 代码评审

  • 是否符合现有模块模式(schema→service→controller→module
  • 是否有多余变量、import、参数
  • 命名是否与项目一致
  • 是否有重复代码或可复用逻辑

Step 2: 安全评审

  • 外部输入是否有注入风险(HTML、Shell、NoSQL
  • 接口是否正确加了 JWT guard 或 @Public()
  • 管理端接口是否有 AdminGuard
  • 修改用户额度/积分是否用 $inc 原子操作
  • 敏感信息是否泄漏到响应或日志中
  • 用户内容输出是否做了转义

Step 3: 性能评审

  • 是否存在 N+1 查询
  • 大表查询是否有索引覆盖
  • 读操作是否该加 .lean()
  • 是否有内存泄漏风险(puppeteer 等资源未释放)

Step 4: 测试验证

cd backend && NODE_OPTIONS="--max-old-space-size=2048" npx nest build
npm test -- --forceExit --detectOpenHandles

Step 5: LSP 诊断

  • Changed files diagnostics clean
  • as any / @ts-ignore / @ts-expect-error