4cd889c081
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
11 KiB
11 KiB
职引 (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 |
微信支付 v3(Native + 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/ |
共享 Schema(pricing 定价、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.ts中APP_GUARD注册) - 白名单: 公开接口加
@Public()装饰器(登录、注册、支付回调、分享访问等) - 管理员: 管理接口加
@UseGuards(AdminGuard)(admin controller 内部) - 当前用户:
@CurrentUser('userId')从 JWT payload 提取用户 ID - JWT 过期: 7 天,在
app.module.ts和每个模块的JwtModule.register中配置
安全硬性要求
- JWT_SECRET 必须来自环境变量,不允许任何硬编码 fallback(已有历史漏洞修复)
- 所有外部输入经过 class-validator
ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }) - 修改用户额度/积分使用
findOneAndUpdate + $inc原子操作,禁止 read-modify-write - 支付订单查询校验 userId 归属,防止 IDOR
- CORS 生产环境必须配置白名单(当前在
main.ts中从CORS_ORIGINS环境变量读取) - 用户内容输出到响应时避免泄漏敏感信息(验证码、密钥等)
- 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.ts(vitest + jsdom)
五、定时任务(3 个 cron,在 schedule 模块)
| 服务 | 周期 | 职责 |
|---|---|---|
VipExpiryService |
每日 00:00 | 扫描过期 VIP 并降级为 free 计划 |
DailyQuestionPushService |
每日 09:00 | 通过微信订阅消息推送每日一题(需配置模板 ID) |
WechatTokenService |
每 2 小时 | 刷新微信 access_token(缓存到 Redis) |
六、项目状态与开发阶段
当前: Phase 0.5 完成,Phase 1(MVP 上线)进行中
| 阶段 | 状态 | 关键交付 |
|---|---|---|
| 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磁场
八、技术细节与坑
- DOMMatrix polyfill:
main.ts顶部有 pdf-parse 所需的浏览器 API polyfill(DOMMatrix / DOMPoint),新增 PDF 相关功能时注意兼容性 - postbuild:
backend/package.json中的postbuild脚本自动复制certs/到dist/src/certs/,这是微信支付证书的必要步骤 - 微信小程序 appid:
zhiyin-app/manifest.json中mp-weixin.appid = wxf466b3c3bc411ffc;开发模式appid = __UNI__DEV__ - 前端 API 调用:
zhiyin-app/src/services/api.ts封装了uni.request,自动处理 token 注入(从uni.getStorageSync('token'))和 401 过期跳转 - 前端环境判断:
config.ts中使用// #ifdef H5/// #ifdef MP-WEIXIN条件编译区分 H5 和小程序 - API 限流: 100 次/60 秒(在
app.module.ts中配置),注意避免在定时任务和批量操作中被限 - 验证码: 开发模式下手机验证码固定为
123456(user.service.ts中实现),生产环境需移除 - 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