ai-chatbot/docs/operations.md
2026-05-28 22:46:41 +08:00

221 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# yedir-ai 运维与质量门禁
本文档记录日常开发、合并前检查、性能烟测和常见故障处理方式。
## 合并前检查
```bash
git fetch github main --prune
pnpm check:branch
pnpm lint
pnpm check:logs
pnpm check:brand
pnpm check:ci
pnpm check:env
pnpm check:secrets
pnpm check:metadata
pnpm check:tests
pnpm test:helpers
pnpm exec tsc --noEmit --pretty false
git diff --check
pnpm check:artifacts
pnpm clean:artifacts
pnpm audit:security
pnpm build
SMOKE_BASE_URL=http://127.0.0.1:3001 pnpm verify:release
```
等价的一键质量门禁:
```bash
pnpm check:quality
```
发布或创建 PR 前的一键验收:
```bash
SMOKE_BASE_URL=http://127.0.0.1:3001 pnpm verify:release
```
`pnpm verify:release` 会串起 `pnpm check:quality`、`pnpm audit:security`、`pnpm build` 和 `pnpm smoke:routes`。它要求显式设置 `SMOKE_BASE_URL`,避免误把路由烟测跑到错误环境。
其中 `pnpm check:artifacts` 会检查 `.DS_Store`、swap 文件、`.env.local`、`.claude/`、migration backup 和 `tsconfig.tsbuildinfo` 等本地污染物是否被 Git 追踪。
`pnpm clean:artifacts` 会清理当前工作区常见本地垃圾文件,例如 `.DS_Store`、swap 文件和 `tsconfig.tsbuildinfo`。它会跳过 `.git`、`node_modules`、`.next`、`.pnpm-store`、`.venv` 等重目录,适合在提交或打包前手动执行。
## 分支与 PR 就绪检查
```bash
git fetch github main --prune
pnpm check:branch
```
`pnpm check:branch` 默认以 `github/main` 为基线,检查当前工作区是否干净、基线 ref 是否存在、当前分支相对 main 的 ahead/behind 状态、受影响文件数量,以及 dry-run merge tree 是否出现冲突标记。它会把 behind main 作为 warning,方便还没决定 rebase/merge 前先看风险;如果发布或合并策略要求必须最新,可使用:
```bash
REQUIRE_UP_TO_DATE=true pnpm check:branch
```
如果远端名不同,可以用 `PR_BASE_REF=origin/main pnpm check:branch` 或 `pnpm check:branch origin/main` 覆盖基线。提交前临时验证未提交改动时,可使用 `ALLOW_DIRTY=true pnpm check:branch` 或 `pnpm check:branch --allow-dirty`。
## CI
`.github/workflows/lint.yml` 是基础质量门禁,运行 `pnpm check:quality`,负责 lint、日志治理、公开交付面品牌治理、CI hygiene、环境变量示例卫生、secret hygiene、package metadata、测试门禁卫生、轻量 helper 回归测试、类型检查、diff hygiene 和 tracked 污染物检查。
CI 和本地提交前检查复用同一个入口,避免规则漂移。
`.github/workflows/dependency-audit.yml` 独立运行 `pnpm audit:security`,通过手动触发守住 high/critical 依赖审计基线。它不依赖任何 secret;当前私有仓库采用手动 CI 策略,避免 push 自动消耗 GitHub Actions 免费额度。
`.github/workflows/build.yml` 独立运行 `pnpm build`,验证生产构建、Next.js route collection 和静态/动态页面边界。该 workflow 使用占位环境变量,不连接真实数据库;数据库迁移仍由部署流程显式执行。
Playwright workflow 独立运行,避免 e2e 依赖、浏览器安装和 secrets 影响基础门禁反馈速度。
Dependabot 每周检查 npm/pnpm 依赖和 GitHub Actions。依赖 PR 仍需按 PR 模板运行 `pnpm check:quality` 和路由烟测,不应自动合并。
## 依赖安全审计
```bash
pnpm audit:security
pnpm audit:security:json
```
`pnpm audit:security` 显式使用官方 npm registry,避免镜像源缺少 audit endpoint 导致误失败。当前依赖安全债务记录在 [dependency-risk-register.md](dependency-risk-register.md)。本命令不嵌入 `pnpm check:quality`,而是由独立 Dependency Audit workflow 手动执行,避免网络型 registry 故障拖垮基础 lint/typecheck 反馈。
## 日志治理
新增或修改已治理文件时不要使用裸 `console.*`。使用:
```ts
import { createLogger } from "@/lib/observability/logger";
const logger = createLogger("scope-name");
logger.info("event name", { count: 1 });
logger.error("event failed", error);
```
客户端使用 `createClientLogger`。生产环境默认静默,除非显式设置 `NEXT_PUBLIC_ENABLE_CLIENT_LOGS=true`。
`pnpm check:logs` 会检查已治理文件是否重新引入裸 console,并验证 token、API Key、URL、base64、password 等敏感值不会明文输出。
## 品牌与模板残留治理
```bash
pnpm check:brand
```
`pnpm check:brand` 只扫描 README、核心 docs、GitHub 模板、workflow 和 package metadata 等公开交付入口。历史方案文档和兼容性 runtime key 不在本门禁范围内,避免为了改名破坏旧用户数据或研发记录。
## CI Hygiene
```bash
pnpm check:ci
```
`pnpm check:ci` 会检查 workflow 是否保留只读权限、concurrency、固定 Ubuntu runner、固定 pnpm 版本、frozen install、cache v4,并禁止 `@latest`、`ubuntu-latest`、`--no-lint` 或构建 fallback 这类不稳定入口回流。
## 环境变量示例治理
```bash
pnpm check:env
```
`pnpm check:env` 会检查 `.env.example` 是否包含关键部署变量、是否存在重复 key、是否把 token/password/API key 这类字段填成疑似真实密钥。
## Secret Hygiene
```bash
pnpm check:secrets
```
`pnpm check:secrets` 会扫描 Git 已追踪文本文件,拦截真实形态的常见 API key、GitHub token、AWS key、Slack token、Authorization/Cookie 长值和私钥块。明显的 `xxxx`、placeholder、example 或 redaction 测试值会被允许,避免误伤文档示例。
## Package Metadata
```bash
pnpm check:metadata
```
`pnpm check:metadata` 会检查 `package.json` 的项目名、描述、许可证、Node/pnpm 版本和 package manager 声明是否符合当前交付基线。`repository/homepage/bugs` 会等 canonical remote 仓库完成重命名并验证后再添加,避免对外链接撒谎。
## 轻量 Helper 回归
```bash
pnpm check:tests
pnpm test:helpers
```
`pnpm check:tests` 会确认轻量 helper 测试仍然使用 no-server 配置、只匹配纯 helper 测试,并且保留在 `pnpm check:quality` 里。
`pnpm test:helpers` 使用 `playwright.helpers.config.ts` 运行不需要浏览器和 Next dev server 的纯 helper 测试,当前覆盖 Canvas chat/detail/upload helper 的关键行为。它已纳入 `pnpm check:quality`,和完整 Playwright e2e 分开,避免基础门禁被数据库、浏览器和登录态拖慢。
## 首页性能烟测
```bash
AUTH_TRUST_HOST=true PORT=3001 pnpm dev
curl -I --max-time 30 http://127.0.0.1:3001/
curl -I --max-time 30 "http://127.0.0.1:3001/api/site-settings?scope=home"
curl -I --max-time 30 "http://127.0.0.1:3001/api/featured?page=1&pageSize=24"
```
首页 HTML 应快速返回。公开轻量接口在数据库慢或不可用时应快速返回缓存或 fallback,不应长时间挂住首屏。
## 上传与对象存储
浏览器图片上传优先走 `/api/files/direct-upload` 获取签名 URL,再由浏览器直传默认 OSS/S3 Bucket;小图或直传失败时才降级到 `/api/files/upload` 服务器中转。排查用户上传失败时,优先按 `clientUploadId` 串联 direct upload、fallback upload 和 `MediaAsset.metadata`。
直传 Bucket 必须配置 CORS,否则大文件分片上传会在浏览器侧失败:
```bash
DIRECT_UPLOAD_CORS_ORIGINS="https://ai.yydd.ai,https://yydd.ai" pnpm storage:configure-upload-cors
```
核心要求:
- Allowed Methods 包含 `GET`、`PUT`、`POST`、`HEAD`。
- Allowed Headers 允许 `*`,因为签名上传会携带 `Content-Type`、`Cache-Control`、ACL 等请求头。
- Exposed Headers 必须包含 `ETag`,否则 multipart upload 无法 complete。
未完成的 multipart upload 会产生隐藏对象存储费用。生产 Bucket 必须开启 lifecycle 自动清理:
```bash
DIRECT_UPLOAD_ABORT_INCOMPLETE_DAYS=2 pnpm storage:configure-upload-lifecycle
```
默认只清理 `uploads/direct/` 前缀下 2 天未完成的分片;如使用自定义前缀,可设置 `DIRECT_UPLOAD_LIFECYCLE_PREFIX`。
当前上传格式支持 JPEG、PNG、WebP,管理员图标额外允许 SVG。HEIC/HEIF 上传会在服务端自动转为高质量 JPEG,避免把转码 WASM 放进前端主包;如果转码失败,会明确提示用户从手机相册导出 JPG/PNG 后再上传。
## 路由回归烟测
推荐使用脚本化检查:
```bash
AUTH_TRUST_HOST=true PORT=3001 pnpm dev
SMOKE_BASE_URL=http://127.0.0.1:3001 pnpm smoke:routes
```
手动检查等价命令:
```bash
curl -I http://127.0.0.1:3001/
curl -I http://127.0.0.1:3001/classic
curl -I http://127.0.0.1:3001/chat/test-id
curl -I http://127.0.0.1:3001/settings
curl -I -X POST http://127.0.0.1:3001/api/files/upload
```
预期:
- `/` 返回 200。
- `/classic` 和 `/chat/test-id` 返回 307 到 `/`。
- `/settings` 未登录返回 307 到 `/login?callbackUrl=%2Fsettings`。
- 上传接口未登录返回 401。
## 常见故障
- `.next/dev/lock` 阻止启动:已有 dev server 持锁,先确认进程归属,不要误杀其他工作区服务。
- 首页接口慢:先看 `Server-Timing`、`X-Cache`、`X-Fallback`,再查数据库连接池和公开接口 fallback。
- 登录 Host 错误:生产配置 `AUTH_URL`;仅在可信代理后设置 `AUTH_TRUST_HOST=true`。
- 上传失败:先用 `clientUploadId` 查日志;再确认 Bucket CORS 暴露 `ETag`、生命周期规则已开启、后台存储配置或环境变量 S3 fallback 至少一组可用。
- 日志泄露风险:不要把完整 prompt、OAuth token、签名 URL、cookie、request body 放进日志 message。