pr-check

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PR Check — Backend Checklist

PR检查 — 后端检查表

Overview

概述

Runs both checklists against the diff:
  1. Static Analysis (B1–B21) — runtime bugs, logic errors, silent failures, test correctness
  2. Design Review (G1–G16) — naming, complexity, documentation, test design, type precision

针对代码差异运行两组检查表:
  1. 静态分析(B1–B21) —— 运行时Bug、逻辑错误、静默失败、测试正确性
  2. 设计评审(G1–G16) —— 命名规范、复杂度、文档、测试设计、类型精度

Required Workflow

必备工作流

Step 1: Understand the diff

步骤1:理解代码差异

Run
git diff main...HEAD
to see all changed files and understand the scope.

执行
git diff main...HEAD
查看所有变更文件,了解修改范围。

Part 1 — Static Analysis (B1–B21)

第一部分 — 静态分析(B1–B21)

B1. Module Initialisation Timing

B1. 模块初始化时机

  • Are any
    const FOO = process.env.BAR
    declarations at module top-level (outside a class)?
  • Env vars must be read via
    ConfigService
    at runtime, not
    process.env
    at import time.
  • 是否有
    const FOO = process.env.BAR
    这样的声明位于模块顶层(类外部)?
  • 环境变量必须在运行时通过
    ConfigService
    读取,而非在导入时通过
    process.env
    读取。

B2. Silent Logic Bugs

B2. 静默逻辑Bug

  • ||
    chains between non-empty strings always resolve to the first operand — use
    as const
    array or union type.
  • Optional fields (
    field?: T
    ) used in comparisons like
    field <= 0
    silently return
    false
    when
    undefined
    .
  • Check if reordering a
    ||
    chain changed which value is evaluated first.
  • 非空字符串之间的
    ||
    链式判断始终会解析为第一个操作数 —— 请使用
    as const
    数组或联合类型。
  • 可选字段(
    field?: T
    )用于
    field <= 0
    这类比较时,当值为
    undefined
    会静默返回
    false
  • 检查
    ||
    链式判断的顺序调整是否改变了值的优先解析逻辑。

B3. Unused Code

B3. 未使用代码

  • Unused imports — especially after refactors.
  • Variables assigned an initial value that is always overwritten before first read — declare without initial value.
  • 未使用的导入 —— 尤其是重构后的残留导入。
  • 被赋值初始值但在首次读取前始终被覆盖的变量 —— 应声明时不赋初始值。

B4. Test Assertion No-Ops

B4. 测试断言无操作

  • Search spec files for
    .toHaveBeenCalled
    without
    ()
    — these silently pass always.
  • Same for
    .toBeDefined
    ,
    .toBeTruthy
    ,
    .toBeFalsy
    ,
    .toBeNull
    without
    ()
    .
  • 在测试文件中搜索没有加
    ()
    .toHaveBeenCalled
    —— 这类代码会始终静默通过。
  • .toBeDefined
    .toBeTruthy
    .toBeFalsy
    .toBeNull
    同理,不加
    ()
    也会无意义通过。

B5. Flaky Tests from Random Data

B5. 随机数据导致的不稳定测试

  • faker
    generating a value that can randomly match the hardcoded value being tested against.
  • Use explicit hardcoded boundary values for mismatch tests.
  • faker
    生成的值可能随机匹配测试中硬编码的预期值。
  • 对于不匹配测试,请使用明确的硬编码边界值。

B6. Redundant Type Definitions

B6. 冗余类型定义

  • New interfaces structurally identical to existing types — search before defining.
  • 新定义的接口与现有类型结构完全一致 —— 定义前请先搜索确认。

B7. Wrong Test Title

B7. 错误的测试标题

  • Test description says "X fails" but the mock actually simulates "Y fails".
  • Test name and
    mockRejectedValue
    /
    mockResolvedValue
    must match.
  • 测试描述写的是“X失败”,但mock实际模拟的是“Y失败”。
  • 测试名称必须与
    mockRejectedValue
    /
    mockResolvedValue
    的逻辑匹配。

B8. Missing Critical Assertions

B8. 缺失关键断言

  • Happy-path tests: are all side effects asserted (DB writes, status updates, service calls)?
  • Guard/skip tests: are downstream methods asserted
    .not.toHaveBeenCalled()
    ?
  • 正常流程测试:是否对所有副作用都做了断言(数据库写入、状态更新、服务调用)?
  • 守卫/跳过测试:是否断言下游方法
    .not.toHaveBeenCalled()

B9. URL Path Construction

B9. URL路径构建

  • Same path string used for both signature generation and the HTTP call?
  • Base URL missing a required path prefix (e.g.,
    /api
    )?
  • 签名生成和HTTP调用是否使用了相同的路径字符串?
  • 基础URL是否缺失必填的路径前缀(例如
    /api
    )?

B10. Status Mapper Completeness

B10. 状态映射完整性

  • Does at least one external status map to each terminal internal state?
  • Any value mapped to
    null
    or unhandled should log + Sentry, not silently disappear.
  • 每个终端内部状态是否至少有一个外部状态与之映射?
  • 任何被映射为
    null
    或未处理的状态都应记录日志并上报Sentry,而非静默消失。

B11. API Response Envelope Type Accuracy

B11. API响应信封类型准确性

  • TypeScript type for each API response must match the actual envelope key from the API docs.
  • Don't assume
    { data: [] }
    — verify the actual key name for every endpoint.
  • 每个API响应的TypeScript类型必须与API文档中的实际信封键名匹配。
  • 不要默认假设是
    { data: [] }
    —— 请验证每个端点的实际键名。

B12. Webhook Controller Must Not Swallow All Exceptions

B12. Webhook控制器不得吞噬所有异常

  • Blanket try-catch returning
    200 OK
    means failed webhooks are silently dropped.
  • Unexpected exceptions should propagate or return 4xx/5xx.
  • 全局try-catch返回
    200 OK
    会导致失败的Webhook被静默丢弃。
  • 意外异常应向上传播或返回4xx/5xx状态码。

B13. No-Op Stubs Must Have No Side Effects

B13. 无操作存根不得有副作用

  • A deferred/stub method must not still call
    updateLastSync
    , fire notifications, or write DB records.
  • A true no-op: only a comment or
    return
    .
  • 延迟/存根方法不得仍调用
    updateLastSync
    、发送通知或写入数据库记录。
  • 真正的无操作:仅保留注释或
    return
    语句。

B14. Duplicate Error Handling in Strategy and Caller

B14. 策略层与调用方重复处理错误

  • If a method catches, logs, Sentries, and rethrows — the caller must NOT catch and log the same error again.
  • 如果一个方法已经捕获、记录日志、上报Sentry并重新抛出异常 —— 调用方不得再次捕获并记录相同的错误。

B15. Enum Constants in Comparisons

B15. 比较时使用枚举常量

  • When a TypeScript enum exists for event types or status strings, use it — don't compare against string literals.
  • 当存在针对事件类型或状态字符串的TypeScript枚举时,请使用枚举 —— 不要直接与字符串字面量比较。

B16. Dead Type Checks in Catch Blocks

B16. Catch块中的无效类型检查

  • instanceof AxiosError
    in a DB/repository catch block will never be true — it's dead code.
  • 在数据库/仓库层的catch块中使用
    instanceof AxiosError
    永远不会为true —— 这是无效代码。

B17. Database Transactions for Multi-Step Writes

B17. 多步骤写入需使用数据库事务

  • Multiple sequential saves (2+) across entities must be wrapped in a TypeORM transaction.
  • 跨实体的多次连续保存(2次及以上)必须包裹在TypeORM事务中。

B18. Race Condition / TOCTOU on State Guards

B18. 状态守卫的竞态条件/TOCTOU问题

  • Check-then-act is not atomic — fix with atomic conditional update or
    SELECT FOR UPDATE
    .
  • 先检查后执行的操作不是原子性的 —— 请使用原子条件更新或
    SELECT FOR UPDATE
    修复。

B19. Missing Null Check on
findOne()

B19.
findOne()
结果缺失空值检查

  • findOne()
    returns
    null
    when no record matches — guard before use.
  • Pattern:
    if (!record) throw new NotFoundException('record not found');
  • findOne()
    在无匹配记录时会返回
    null
    —— 使用前必须做守卫检查。
  • 推荐模式:
    if (!record) throw new NotFoundException('record not found');

B20. Credentials in Documentation Files

B20. 文档文件中包含凭据

  • Real API tokens in
    .md
    files are committed to git history permanently.
  • Use clearly fake placeholders:
    YOUR_BEARER_TOKEN_HERE
    ,
    <api-token>
    .
  • .md
    文件中的真实API令牌会被永久提交到git历史中。
  • 请使用明确的假占位符:
    YOUR_BEARER_TOKEN_HERE
    <api-token>

B21. Input Normalization Consistency

B21. 输入规范化一致性

  • New flows must normalize user-provided strings (email, username) the same way as existing flows.

  • 新流程必须与现有流程以相同方式规范化用户提供的字符串(邮箱、用户名)。

Part 2 — Design Review (G1–G16)

第二部分 — 设计评审(G1–G16)

G1. Method Complexity

G1. 方法复杂度

  • Methods longer than ~40 lines with multiple concerns — extract to focused helpers.
  • 超过约40行且包含多个关注点的方法 —— 应拆分为专注的辅助方法。

G2. Named Constants

G2. 命名常量

  • Magic strings for status/state values — check if constants already exist.
  • 状态/状态值使用魔法字符串 —— 请检查是否已有对应的常量定义。

G3. Naming Specificity

G3. 命名特异性

  • Vague or mismatched names — method named for X that contains logic for Y.
  • 模糊或不匹配的命名 —— 方法名标注为X,但实际包含Y的逻辑。

G4. Documentation

G4. 文档

  • New method similar to an existing one — explain the difference in a comment.
  • New state transitions — update state machine or architecture docs.
  • 与现有方法类似的新方法 —— 请在注释中说明差异。
  • 新的状态转换 —— 请更新状态机或架构文档。

G5. Test Data Realism

G5. 测试数据真实性

  • Numeric fields (price, quantity, dimensions) using
    faker.string.alphanumeric()
    instead of number generators.
  • Currency fields using random strings instead of
    faker.finance.currencyCode()
    .
  • 数值字段(价格、数量、尺寸)使用
    faker.string.alphanumeric()
    而非数值生成器。
  • 货币字段使用随机字符串而非
    faker.finance.currencyCode()

G6. Test Naming Clarity

G6. 测试命名清晰度

  • Vague words: "completely", "properly", "correctly" without specifics.
  • Preferred:
    should <do something> when <condition>
    .
  • 使用模糊词汇:“completely”、“properly”、“correctly”但未说明具体内容。
  • 推荐格式:
    should <执行操作> when <条件>

G7. No Real URLs or Credentials in Tests or Service Defaults

G7. 测试或服务默认值中不得包含真实URL或凭据

  • All test URLs must be clearly dummy (
    https://example.com
    ,
    https://test.invalid
    ).
  • No production-looking base URL hardcoded as a service default.
  • 所有测试URL必须是明确的虚拟地址(
    https://example.com
    https://test.invalid
    )。
  • 服务默认值中不得硬编码类似生产环境的基础URL。

G8. Test Assertion Completeness

G8. 测试断言完整性

  • Crypto/signature operations: validate the output value, not just that the function ran.
  • Retry/token-refresh flows: add a test for when the retry itself also fails.
  • 加密/签名操作:请验证输出值,而非仅验证函数是否执行。
  • 重试/令牌刷新流程:请添加重试本身也失败的测试场景。

G9.
.env.example
Completeness

G9.
.env.example
完整性

  • All new env vars added to
    .env.example
    with a descriptive placeholder.
  • 所有新增的环境变量都应添加到
    .env.example
    中,并附上描述性占位符。

G10. Type Precision

G10. 类型精度

  • ||
    chains that should be
    as const
    arrays or union literal types.
  • Optional fields that should be required.
  • 应改为
    as const
    数组或联合字面量类型的
    ||
    链式判断。
  • 应设为必填的可选字段。

G11. Logical Grouping

G11. 逻辑分组

  • New types/constants placed in the section matching their domain.
  • 新类型/常量应放置在与其领域匹配的代码段中。

G12. Idempotency of External Calls in Retry Contexts

G12. 重试场景中外调用用的幂等性

  • In cron/retry-driven pushes: if the call succeeds externally but fails to record locally, the next retry creates a duplicate.
  • 在定时任务/重试驱动的推送中:如果外部调用成功但本地记录失败,下一次重试会创建重复数据。

G13. Log Level for Security Failures

G13. 安全失败的日志级别

  • Failed HMAC validation, invalid auth →
    error
    , not
    warn
    .
  • HMAC验证失败、无效认证 → 应使用
    error
    级别日志,而非
    warn

G14. Use Existing Helpers Consistently

G14. 一致使用现有辅助工具

  • Before constructing a cache key or identifier inline, check if a helper already exists.
  • 在手动构造缓存键或标识符前,请检查是否已有对应的辅助工具。

G15. YAGNI — Avoid Implementing Unbuilt Features

G15. YAGNI原则 —— 避免实现未规划的功能

  • Constants or fields for features not yet built should be deferred.
  • 针对尚未开发的功能的常量或字段应延迟添加。

G16. Database Schema & Migration Quality

G16. 数据库 schema 与迁移质量

  • Entity column decorators must match the actual DB type (
    timestamptz
    ,
    bigint
    ,
    smallint
    ).
  • Numeric columns for whole numbers: use
    int
    /
    bigint
    /
    smallint
    , not
    float
    /
    decimal
    .
  • Migration
    varchar
    columns: specify explicit length where the domain has a known maximum.
  • Column defaults must match nullable design.
  • Index columns must match actual query patterns — UNIQUE index on lookup columns.

  • 实体列装饰器必须与实际数据库类型匹配(
    timestamptz
    bigint
    smallint
    )。
  • 用于整数的数值列:请使用
    int
    /
    bigint
    /
    smallint
    ,而非
    float
    /
    decimal
  • 迁移中的
    varchar
    列:当领域有已知最大值时,请指定明确长度。
  • 列默认值必须与可空设计匹配。
  • 索引列必须与实际查询模式匹配 —— 查找列应添加UNIQUE索引。

Step 2: Report Findings

步骤2:报告发现的问题

Group by part. For each issue:
[B1] path/to/file.ts:3
Severity: High
Issue: reads process.env at module-load time before ConfigModule bootstraps.
Fix: inject ConfigService, read inside method.

[G3] path/to/file.ts:42
Issue: method name is too vague — doesn't communicate what it does without reading the body.
Fix: rename to something that describes the actual behaviour.
按部分分组。每个问题格式如下:
[B1] path/to/file.ts:3
Severity: High
Issue: reads process.env at module-load time before ConfigModule bootstraps.
Fix: inject ConfigService, read inside method.

[G3] path/to/file.ts:42
Issue: method name is too vague — doesn't communicate what it does without reading the body.
Fix: rename to something that describes the actual behaviour.

Step 3: Final Verdict

步骤3:最终结论

Static analysis:  X high, Y medium, Z low
Design review:    X blocking, Y nit

Overall: READY / NEEDS CHANGES

Static analysis:  X high, Y medium, Z low
Design review:    X blocking, Y nit

Overall: READY / NEEDS CHANGES

Individual Skills

独立技能项

Run separately for a focused check:
  • pr-check-static
    — B1–B21 static analysis only
  • pr-check-style
    — G1–G16 design patterns only
  • pr-check-frontend
    — F1–F16 React/Vue/Next.js/Tailwind
可单独运行以进行针对性检查:
  • pr-check-static
    —— 仅运行B1–B21静态分析项
  • pr-check-style
    —— 仅运行G1–G16设计模式项
  • pr-check-frontend
    —— 运行F1–F16 React/Vue/Next.js/Tailwind相关检查