code-review

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Code Review Methodology

代码评审方法论

Systematic pre-PR code review for the project codebase. Identifies critical issues with focus on TRPC patterns, TanStack Router, Drizzle ORM, and security best practices.
针对项目代码库的系统化PR前代码评审。重点关注TRPC模式、TanStack Router、Drizzle ORM和安全最佳实践,识别关键问题。

Review Process

评审流程

  1. Identify Scope — Determine what code to review
  2. Scan Changes — Analyze against project-specific patterns
  3. Verify with Exa & Context7 — Validate uncertain patterns
  4. Categorize Findings — Organize by severity (Critical, Major, Minor)
  5. Generate Report — Structured report with actionable feedback
  6. Run Automated Checks — Execute
    bun run check

  1. 确定范围 — 明确需要评审的代码内容
  2. 扫描变更 — 对照项目专属模式进行分析
  3. 通过Exa & Context7验证 — 对不确定的模式进行验证
  4. 分类发现的问题 — 按严重程度(关键、主要、次要)整理
  5. 生成报告 — 包含可执行反馈的结构化报告
  6. 运行自动化检查 — 执行
    bun run check

Step 1: Identify Scope

步骤1:确定范围

Ask the user what to review:
  1. Recent commits (default):
    git log -5 --oneline && git diff HEAD~5..HEAD --stat
  2. Specific files/directories: User-provided paths
  3. Branch comparison:
    git diff main..HEAD --stat

询问用户需要评审的内容:
  1. 最近提交记录(默认):
    git log -5 --oneline && git diff HEAD~5..HEAD --stat
  2. 特定文件/目录:用户提供的路径
  3. 分支对比
    git diff main..HEAD --stat

Step 2: Vivus-Specific Review Categories

步骤2:项目专属评审类别

1. TRPC Patterns

1. TRPC模式

Check against skill:
trpc-patterns
Critical patterns to verify:
typescript
// ✅ Correct - Using RouterOutputs/RouterInputs
type SessionData = RouterOutputs["adminAuthSessions"]["listTokens"]["sessions"][0];

// ❌ Wrong - Manual type definitions
type SessionData = { sessionId: string; ... };
typescript
// ✅ Correct - Using error helpers
throw notFoundError("Project not found");

// ❌ Wrong - Manual TRPCError
throw new TRPCError({ code: "NOT_FOUND", message: "..." });
typescript
// ✅ Correct - protectedMemberAccessProcedure for org-scoped
export const router = {
  getOrgData: protectedMemberAccessProcedure
    .input(z.object({ organizationId: z.string() }))
    .query(...)
}

// ❌ Wrong - Manual membership check in protectedProcedure
typescript
// ✅ Correct - Inline simple schemas with common types
role: z.enum([OrganizationRoles.Owner, OrganizationRoles.Admin]);

// ❌ Wrong - Hardcoded enum values
role: z.enum(["owner", "admin"]);
SQL Query Optimization:
typescript
// ✅ Correct - Single query with JOINs
const result = await db.select({...}).from(membersTable)
  .innerJoin(organizationsTable, eq(...))
  .leftJoin(projectsTable, eq(...))

// ❌ Wrong - Multiple separate queries (N+1)
const orgs = await db.select().from(organizationsTable);
const members = await db.select().from(membersTable);

对照Skill检查:
trpc-patterns
需要验证的关键模式:
typescript
// ✅ 正确用法 - 使用RouterOutputs/RouterInputs
type SessionData = RouterOutputs["adminAuthSessions"]["listTokens"]["sessions"][0];

// ❌ 错误用法 - 手动定义类型
type SessionData = { sessionId: string; ... };
typescript
// ✅ 正确用法 - 使用错误助手函数
throw notFoundError("Project not found");

// ❌ 错误用法 - 手动创建TRPCError
throw new TRPCError({ code: "NOT_FOUND", message: "..." });
typescript
// ✅ 正确用法 - 针对组织范围使用protectedMemberAccessProcedure
export const router = {
  getOrgData: protectedMemberAccessProcedure
    .input(z.object({ organizationId: z.string() }))
    .query(...)
}

// ❌ 错误用法 - 在protectedProcedure中手动检查成员资格
typescript
// ✅ 正确用法 - 结合通用类型内联简单枚举
role: z.enum([OrganizationRoles.Owner, OrganizationRoles.Admin]);

// ❌ 错误用法 - 硬编码枚举值
role: z.enum(["owner", "admin"]);
SQL查询优化:
typescript
// ✅ 正确用法 - 使用JOIN的单查询
const result = await db.select({...}).from(membersTable)
  .innerJoin(organizationsTable, eq(...))
  .leftJoin(projectsTable, eq(...))

// ❌ 错误用法 - 多个独立查询(N+1问题)
const orgs = await db.select().from(organizationsTable);
const members = await db.select().from(membersTable);

2. TanStack Router & Query Patterns

2. TanStack Router & Query模式

Check against skill:
tanstack-frontend
Critical patterns to verify:
typescript
// ✅ Correct - TRPC v11 pattern with .queryOptions()
const { data } = useSuspenseQuery(trpc.organization.getById.queryOptions({ id }));

// ❌ Wrong - Old pattern (doesn't exist in v11)
const { data } = trpc.organization.getById.useQuery({ id });
typescript
// ✅ Correct - Prefetch critical data with await
loader: async ({ context, params }) => {
  await context.queryClient.prefetchQuery(
    context.trpc.organization.getById.queryOptions({ id: params.id })
  );
  // Secondary data - void for optimization
  void context.queryClient.prefetchQuery(
    context.trpc.analytics.getStats.queryOptions({ id: params.id })
  );
}

// ❌ Wrong - Sequential await (slow)
await context.queryClient.prefetchQuery(...);
await context.queryClient.prefetchQuery(...);
await context.queryClient.prefetchQuery(...);

// ❌ Wrong - All void (component will suspend)
void context.queryClient.prefetchQuery(...);  // critical data!
typescript
// ✅ Correct - Props type naming
type Props = { isOpen: boolean; onClose: () => void; };

// ❌ Wrong - Component-specific props naming
type DeleteMemberModalProps = { ... };
typescript
// ✅ Correct - Cache invalidation
await queryClient.invalidateQueries({
  queryKey: trpc.organization.queryKey(),
});

对照Skill检查:
tanstack-frontend
需要验证的关键模式:
typescript
// ✅ 正确用法 - TRPC v11的.queryOptions()模式
const { data } = useSuspenseQuery(trpc.organization.getById.queryOptions({ id }));

// ❌ 错误用法 - 旧模式(v11中已移除)
const { data } = trpc.organization.getById.useQuery({ id });
typescript
// ✅ 正确用法 - 用await预取关键数据
loader: async ({ context, params }) => {
  await context.queryClient.prefetchQuery(
    context.trpc.organization.getById.queryOptions({ id: params.id })
  );
  // 次要数据 - 使用void优化
  void context.queryClient.prefetchQuery(
    context.trpc.analytics.getStats.queryOptions({ id: params.id })
  );
}

// ❌ 错误用法 - 顺序await(速度慢)
await context.queryClient.prefetchQuery(...);
await context.queryClient.prefetchQuery(...);
await context.queryClient.prefetchQuery(...);

// ❌ 错误用法 - 全部用void(组件会挂起)
void context.queryClient.prefetchQuery(...);  // 这是关键数据!
typescript
// ✅ 正确用法 - Props类型命名
type Props = { isOpen: boolean; onClose: () => void; };

// ❌ 错误用法 - 组件专属Props命名
type DeleteMemberModalProps = { ... };
typescript
// ✅ 正确用法 - 缓存失效
await queryClient.invalidateQueries({
  queryKey: trpc.organization.queryKey(),
});

3. Code Deduplication (DRY)

3. 代码去重(DRY原则)

Identify duplicate or near-duplicate code:
  • Same logic implemented in multiple files with different approaches
  • Copy-pasted functions with minor variations
  • Repeated patterns that could be extracted to shared utilities
When to extract:
  • Same logic appears in 2+ locations
  • Functions differ only in minor details (parameterize instead)
  • Utility is general enough to be reused
Where to place shared code:
  • packages/services/src/
    — Cross-service shared utilities
  • packages/common/src/
    — Cross-package shared types/utilities
  • Same-directory
    utils.ts
    — Local module utilities

识别重复或近似重复的代码:
  • 同一逻辑在多个文件中用不同方式实现
  • 复制粘贴后仅做微小修改的函数
  • 可提取为共享工具的重复模式
提取时机:
  • 同一逻辑出现在2个及以上位置
  • 函数仅在细节上有差异(应参数化处理)
  • 工具函数具有足够通用性可被复用
共享代码存放位置:
  • packages/services/src/
    — 跨服务共享工具
  • packages/common/src/
    — 跨包共享类型/工具
  • 同目录下的
    utils.ts
    — 本地模块工具

4. Code Quality & Style

4. 代码质量与风格

Check CLAUDE.md conventions:
  • Imports: Always absolute (
    @/path
    or
    @project/*
    ), never relative in
    apps/web-app/src
  • Nullish coalescing: Use
    ??
    not
    ||
    for defaults
  • Bun APIs: Use
    Bun.file()
    ,
    Bun.spawn()
    instead of Node.js polyfills
  • File naming: kebab-case (
    contact-form.tsx
    , not
    ContactForm.tsx
    )
  • Types: Use
    type
    not
    interface
    unless extending
  • Logger: Use
    @project/logger
    for backend,
    console.log/error
    is OK for frontend React components
  • No barrel files: Don't create
    index.ts
    that only re-exports (causes circular imports, slow dev)
DO NOT REPORT these as issues (they are acceptable):
  • packages/*/src/index.ts
    using
    export *
    — Package entry points are allowed exceptions
  • Relative imports (
    ../
    ) inside
    packages/
    directories — Only apps/web-app requires absolute imports
  • console.log/error
    in React components (frontend) — Only backend code requires
    @project/logger

检查CLAUDE.md约定:
  • 导入方式: 始终使用绝对路径(
    @/path
    @project/*
    ),
    apps/web-app/src
    中禁止使用相对路径
  • 空值合并: 默认值使用
    ??
    而非
    ||
  • Bun API: 使用
    Bun.file()
    Bun.spawn()
    替代Node.js兼容层
  • 文件命名: 使用短横线命名法(
    contact-form.tsx
    ,而非
    ContactForm.tsx
  • 类型定义: 除非需要扩展,否则使用
    type
    而非
    interface
  • 日志工具: 后端使用
    @project/logger
    ,前端React组件可使用
    console.log/error
  • 禁止桶文件: 不要创建仅用于重新导出的
    index.ts
    (会导致循环导入、减慢开发速度)
以下情况无需报告(属于可接受范围):
  • packages/*/src/index.ts
    使用
    export *
    — 包入口文件允许例外
  • packages/
    目录内使用相对导入(
    ../
    ) — 仅
    apps/web-app
    要求绝对导入
  • React组件(前端)中使用
    console.log/error
    — 仅后端代码要求使用
    @project/logger

5. Security

5. 安全检查

Critical checks:
  • Hardcoded secrets/API keys:
    grep -iE "api[_-]?key|password|secret|token"
  • SQL injection: String interpolation in queries
  • Missing auth: Endpoints without
    protectedProcedure
    or
    protectedMemberAccessProcedure
  • Sensitive data in logs
  • Missing input validation
Use error helpers from
@/infrastructure/errors
:
  • badRequestError()
    ,
    unauthorizedError()
    ,
    forbiddenError()
    ,
    notFoundError()

关键检查项:
  • 硬编码的密钥/API密钥:
    grep -iE "api[_-]?key|password|secret|token"
  • SQL注入:查询中使用字符串插值
  • 缺失认证:未使用
    protectedProcedure
    protectedMemberAccessProcedure
    的端点
  • 日志中包含敏感数据
  • 缺失输入验证
使用
@/infrastructure/errors
中的错误助手函数:
  • badRequestError()
    unauthorizedError()
    forbiddenError()
    notFoundError()

6. Performance

6. 性能检查

Database:
  • N+1 queries (multiple queries that could be JOINs)
  • Missing indexes on frequently queried columns
  • Sequential API calls instead of
    Promise.all()
Frontend:
  • Missing prefetch in loaders
  • Sequential
    await
    instead of
    Promise.all()
    in loaders
  • fetchQuery
    when
    prefetchQuery
    would suffice

数据库层面:
  • N+1查询(可通过JOIN合并的多个查询)
  • 频繁查询的列缺少索引
  • 使用顺序API调用而非
    Promise.all()
前端层面:
  • Loader中缺失预取逻辑
  • Loader中使用顺序
    await
    而非
    Promise.all()
  • 可用
    prefetchQuery
    时使用了
    fetchQuery

7. Testing

7. 测试检查

Check for:
  • New TRPC endpoints without tests in
    packages/services/src/__tests__/
  • New components without tests
  • Missing E2E tests for critical flows

检查内容:
  • 新增TRPC端点但未在
    packages/services/src/__tests__/
    中添加测试
  • 新增组件但未添加测试
  • 关键流程缺失E2E测试

8. Effect Patterns (if changes include Effect code)

8. Effect模式(若变更包含Effect代码)

Check against skill:
effect-ts
Applies to:
packages/services/
,
effect-runtime.ts
, files with
Effect.gen
,
Context.Tag
typescript
// ✅ Correct - Service with @project namespace
export class MyService extends Context.Tag("@project/MyService")<...>() {}

// ❌ Wrong - Missing namespace
export class MyService extends Context.Tag("MyService")<...>() {}
typescript
// ✅ Correct - Effect.fn for tracing
const doSomething = Effect.fn("MyService.doSomething")(
  function* (params) { ... }
);

// ❌ Wrong - No tracing
const doSomething = (params) => Effect.gen(function* () { ... });
typescript
// ✅ Correct - Schema.TaggedError
export class MyError extends Schema.TaggedError<MyError>()("MyError", {...}) {}

// ❌ Wrong - Data.TaggedError (less Schema interop)
export class MyError extends Data.TaggedError("MyError")<{...}> {}
typescript
// ✅ Correct - ManagedRuntime for TRPC
import { runtime } from "@/infrastructure/effect-runtime";
await runtime.runPromise(Effect.gen(function* () { ... }));

// ❌ Wrong - Inline provide per request
await Effect.runPromise(effect.pipe(Effect.provide(ServiceLive)));
For comprehensive Effect analysis, run:
/scan-effect-solutions

对照Skill检查:
effect-ts
适用范围:
packages/services/
effect-runtime.ts
、包含
Effect.gen
Context.Tag
的文件
typescript
// ✅ 正确用法 - 使用@project命名空间的服务
export class MyService extends Context.Tag("@project/MyService")<...>() {}

// ❌ 错误用法 - 缺失命名空间
export class MyService extends Context.Tag("MyService")<...>() {}
typescript
// ✅ 正确用法 - 使用Effect.fn实现追踪
const doSomething = Effect.fn("MyService.doSomething")(
  function* (params) { ... }
);

// ❌ 错误用法 - 未实现追踪
const doSomething = (params) => Effect.gen(function* () { ... });
typescript
// ✅ 正确用法 - 使用Schema.TaggedError
export class MyError extends Schema.TaggedError<MyError>()("MyError", {...}) {}

// ❌ 错误用法 - 使用Data.TaggedError(Schema互操作性差)
export class MyError extends Data.TaggedError("MyError")<{...}> {}
typescript
// ✅ 正确用法 - 为TRPC使用ManagedRuntime
import { runtime } from "@/infrastructure/effect-runtime";
await runtime.runPromise(Effect.gen(function* () { ... }));

// ❌ 错误用法 - 每个请求内联提供依赖
await Effect.runPromise(effect.pipe(Effect.provide(ServiceLive)));
如需全面的Effect分析,执行:
/scan-effect-solutions

Verify Uncertain Patterns

验证不确定的模式

Use Exa Search for real-world patterns:
Query: "React useEffect cleanup best practices"
Query: "TRPC v11 queryOptions pattern"
Use Context7 for official docs:
1. context7-resolve-library-id(libraryName: "tanstack-query")
2. context7-get-library-docs(context7CompatibleLibraryID: "...", topic: "prefetchQuery")

使用Exa Search查找真实场景模式:
查询:"React useEffect清理最佳实践"
查询:"TRPC v11 queryOptions模式"
使用Context7获取官方文档:
1. context7-resolve-library-id(libraryName: "tanstack-query")
2. context7-get-library-docs(context7CompatibleLibraryID: "...", topic: "prefetchQuery")

Finding Severity Classification

问题严重程度分类

CRITICAL (Must Fix Before Merge)

关键(合并前必须修复)

  • Security vulnerabilities
  • SQL injection, hardcoded secrets
  • Missing authentication on protected endpoints
  • Breaking changes to public APIs
  • 安全漏洞
  • SQL注入、硬编码密钥
  • 受保护端点缺失认证
  • 对公共API的破坏性变更

MAJOR (Should Fix)

主要(建议修复)

  • Wrong TRPC v11 patterns (
    .useQuery
    instead of
    .queryOptions
    )
  • N+1 database queries
  • Missing prefetch causing slow page loads
  • Manual types instead of
    RouterInputs
    /
    RouterOutputs
  • Code duplication — same logic in multiple files (DRY violation)
  • TRPC v11模式错误(使用
    .useQuery
    而非
    .queryOptions
  • N+1数据库查询
  • 缺失预取导致页面加载缓慢
  • 手动定义类型而非使用
    RouterInputs
    /
    RouterOutputs
  • 代码重复——同一逻辑在多个文件中实现(违反DRY原则)

MINOR (Consider Fixing)

次要(考虑修复)

  • Style inconsistencies
  • Missing documentation
  • Non-critical refactoring

  • 风格不一致
  • 缺失文档
  • 非关键重构

Report Template

报告模板

markdown
undefined
markdown
undefined

Code Review Report

代码评审报告

Scope: [What was reviewed] Date: [Current date]

范围: [评审内容] 日期: [当前日期]

CRITICAL ISSUES

关键问题

[List with file:line, description, fix]

[列出文件:行号、描述、修复方案]

MAJOR ISSUES

主要问题

[List with file:line, description, fix]

[列出文件:行号、描述、修复方案]

MINOR ISSUES

次要问题

[List with file:line, brief description]

[列出文件:行号、简要描述]

POSITIVE OBSERVATIONS

积极发现

  • [Good patterns found]

  • [发现的良好模式]

SUMMARY

总结

Assessment: [APPROVE / NEEDS_WORK / REJECT] Next steps: [Specific actions]
评估结果: [通过 / 需要改进 / 拒绝] 下一步: [具体行动]

Quick Stats

快速统计

  • Files reviewed: [N]
  • Issues: Critical: [N], Major: [N], Minor: [N]

---
  • 评审文件数:[N]
  • 问题数量:关键:[N],主要:[N],次要:[N]

---

Assessment Criteria

评估标准

APPROVE
  • No critical issues
  • TRPC and TanStack patterns correct
  • bun run check
    passes
NEEDS_WORK
  • Major pattern violations
  • Missing tests for new functionality
  • Performance issues
REJECT
  • Security vulnerabilities
  • Breaking changes without migration
  • Fundamental design flaws

通过
  • 无关键问题
  • TRPC和TanStack模式正确
  • bun run check
    执行通过
需要改进
  • 存在主要模式违规
  • 新增功能缺失测试
  • 存在性能问题
拒绝
  • 存在安全漏洞
  • 无迁移方案的破坏性变更
  • 基础设计缺陷

Related Skills

相关Skill

  • trpc-patterns
    — TRPC router patterns, procedures, error handling
  • tanstack-frontend
    — Router, Query, Form patterns
  • effect-ts
    — Effect services, layers, ManagedRuntime, error handling
  • scan-effect-solutions
    — Deep Effect compliance scan
  • production-troubleshooting
    — Performance investigation
  • trpc-patterns
    — TRPC路由模式、流程、错误处理
  • tanstack-frontend
    — 路由、查询、表单模式
  • effect-ts
    — Effect服务、层级、ManagedRuntime、错误处理
  • scan-effect-solutions
    — 深度Effect合规扫描
  • production-troubleshooting
    — 性能排查