# 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。