name: code-reviewer description: Reviews code for bugs, security vulnerabilities, and quality issues. MUST be invoked automatically after completing a coding task (feature, bug fix, or refactor) - do not wait for user to request it. user-invocable: true
Code Review
Review recent code changes for quality, security, maintainability, and adherence to project patterns.
Instructions
1. Get Recent Changes
Run git diff to see uncommitted changes. If no uncommitted changes, run git diff HEAD~1 to review the last commit.
Focus on modified files and analyze them thoroughly.
2. Review Checklist
Apply this checklist to all changed code:
Security (CRITICAL)
- Hardcoded credentials (API keys, passwords, tokens)
- SQL injection risks (string concatenation in queries - should use Knex parameterized queries)
- XSS vulnerabilities (unescaped user input in responses)
- Missing input validation (DTOs should use Zod schemas)
- Authentication bypasses (missing
@UseGuards(JwtAuthGuard)) - Path traversal risks (user-controlled file paths)
- CSRF vulnerabilities
- Insecure dependencies (outdated, vulnerable)
Clean Architecture (CRITICAL)
Clean Architecture - API (API only):
Dependency Rule Violations:
- ❌
core/MUST NEVER import fromadapters/- Check all imports in core files - ❌ UseCases depending on concrete implementations (e.g.,
SqlRepository) instead of interfaces - ❌ Domain models importing infrastructure code
- ✅ Core should only import from
core/,shared-kernel/, or"shared"package
Layer Violations:
- Controllers containing business logic (should only handle HTTP → UseCase → HTTP)
- Business logic in repositories/queries (should be in UseCases)
- Direct database access in controllers (should go through UseCases)
Clean Architecture - Web (Web only):
Dependency Rule Violations:
- ❌
core/importing frominfrastructure/orviews/directories - ❌ Presentational components with business logic
- ✅ Core should only import from
core/or"shared"package
Example violation:
// BAD - core importing from infrastructure
// File: src/features/create-site/core/createSite.reducer.ts
import { HttpSiteService } from "../../infrastructure/site-service/HttpSiteService";
// GOOD - core depending on interface only
// File: src/features/create-site/core/createSite.reducer.ts
import type { SiteService } from "./gateways/SiteService";
Redux Architecture (CRITICAL - Web only)
ESTABLISHED Pattern:
- ❌ Refactoring Redux to other state management (Zustand, Jotai, MobX)
- ❌ Using
createSlicefor new code (legacy - maintenance only) - ❌ Actions using imperative tense (
completeStep,fetchData) - ✅ Use event-based Redux with
createReducer - ✅ Actions in passive tense (
stepCompleted,dataFetched)
Example violations:
// BAD - createSlice in new code
export const newFeatureSlice = createSlice({
name: 'newFeature',
initialState,
reducers: { /* ... */ }
});
// GOOD - createReducer for new code
export const newFeatureReducer = createReducer(initialState, (builder) => {
builder.addCase(featureDataFetched, (state, action) => { /* ... */ });
});
// BAD - imperative action names
export const fetchSiteData = createAction("site/fetch");
export const completeSiteCreation = createAction("site/complete");
// GOOD - passive/event-based action names
export const siteDataFetched = createAction("site/dataFetched");
export const siteCreationCompleted = createAction("site/creationCompleted");
UseCase Pattern (CRITICAL - API only)
Result Pattern:
- ❌ UseCases not implementing
UseCase<Request, TResult<Response, Error>> - ❌ UseCases not returning
TResult<Data, Error> - ❌ Using
throwfor domain errors instead offail("ErrorType") - ❌ Error types that are action-based ("CreateFailed") instead of state-based ("AlreadyExists", "NotFound")
- ✅ All UseCases should use
success(data)orfail("ErrorType")
Dependency Injection:
- ❌ UseCases depending on concrete classes (e.g.,
SqlSiteRepository) instead of interfaces - ❌ Missing gateway interfaces in
core/gateways/ - ✅ Constructor parameters should be typed as interfaces, not concrete classes
Controller Pattern (CRITICAL - API only)
DTOs:
- ❌ DTOs defined in controller files (should be in
/packages/shared/src/api-dtos/) - ❌ Missing Zod schema validation with
ZodValidationPipe - ❌ Business logic validation in DTOs (should be in UseCases)
- ✅ All request/response DTOs should be in shared package with both schema + type export
Authentication:
- ❌ Routes missing
@UseGuards(JwtAuthGuard)(unless explicitly public) - ❌ Unprotected routes without clear justification
Result Mapping:
- ❌ Not handling Result errors (missing
if (result.isFailure())check) - ❌ Inconsistent HTTP status mapping (e.g.,
*NotFoundshould throwNotFoundException) - ❌ Returning domain entities instead of ViewModels
Container/Presentational Pattern (HIGH - Web only)
ViewData Pattern:
- ❌ Multiple
useAppSelectorcalls in container - ❌ Selectors not following
select{Feature}ViewDatanaming - ❌ Presentational components using Redux hooks
- ✅ Single ViewData selector per container
- ✅ Presentational components receive all data via props
Example violations:
// BAD - multiple selectors in container
const Container = () => {
const sites = useAppSelector(selectSites);
const loading = useAppSelector(selectLoading);
const error = useAppSelector(selectError);
// ...
};
// GOOD - single ViewData selector
const Container = () => {
const viewData = useAppSelector(selectSitesViewData);
return <SitesPage viewData={viewData} />;
};
// BAD - presentational component with Redux
const SitesPage = () => {
const sites = useAppSelector(selectSites); // ❌ NO REDUX IN PRESENTATIONAL
return <div>{sites.map(...)}</div>;
};
// GOOD - presentational component with props only
const SitesPage = ({ viewData }: { viewData: SitesViewData }) => {
return <div>{viewData.sites.map(...)}</div>;
};
Redux Hooks (HIGH - Web only)
- ❌ Using untyped
useSelectororuseDispatchfrom react-redux - ✅ Always use
useAppSelectoranduseAppDispatchfrom@/shared/views/hooks/store.hooks
Example violation:
// BAD - untyped hooks
import { useSelector, useDispatch } from 'react-redux';
const data = useSelector(state => state.feature); // No type safety
const dispatch = useDispatch();
// GOOD - typed hooks
import { useAppSelector, useAppDispatch } from '@/shared/views/hooks/store.hooks';
const data = useAppSelector(selectFeatureData); // Fully typed
const dispatch = useAppDispatch();
CQS (Command-Query Separation) (HIGH - API only)
Repository vs Query:
- ❌ Repository interfaces mixing reads and writes
- ❌ Query interfaces with write methods
- ❌ Write UseCases using Query interfaces for data modification
- ✅ Write operations should use Repository, read-only operations should use Query
Database Patterns (CRITICAL - API only)
Migrations:
- ❌ Direct database schema changes without migration
- ❌ Missing
down()function in migrations - ❌ Missing indexes on foreign keys or frequently queried columns
Table Types:
- ❌ New tables without corresponding
Sql*type intableTypes.d.ts - ❌ Using
anytype for SQL operations - ❌ Optional properties (
?:) instead of nullable (| null) in table types - ❌ Using
stringfor timestamp columns (should beDate- Knex auto-converts) - ✅ All SQL table types should use
snake_casecolumn names
Naming Convention:
- ❌ Database columns using
camelCase(should besnake_case) - ❌ Application properties using
snake_case(should becamelCase) - ✅ Repository code should map between
snake_case(DB) andcamelCase(app)
Transactions:
- ❌ Multi-table operations without transactions
- ✅ Operations spanning multiple tables should use
sqlConnection.transaction()
Testing Pattern (CRITICAL)
Testing - API (API only):
InMemory Implementations:
- ❌ New Repository/Query interfaces without InMemory implementation
- ❌ Missing test helper methods (prefixed with
_) in InMemory classes - ❌ Unit tests accessing real database (should use InMemory)
Unit Tests:
- ❌ UseCase instantiation in
beforeEach()(should be in eachit()) - ❌ Using
toMatchObject()whentoEqual()is appropriate (less exhaustive) - ❌ Missing failure path tests (only testing happy path)
- ❌ Not verifying side effects (e.g., data saved, not saved on failure)
- ❌ Using real services (random IDs, current dates) instead of deterministic ones
Event Testing:
- ❌ Success paths not asserting published events
- ❌ Error paths not asserting NO events published
- ❌ Event assertions without complete type (should use
expect().toEqual<EventType>(...)) - ✅ Use
InMemoryEventPublisherand asserteventPublisher.eventslength and content
Integration Tests:
- ❌ SQL Repository/Query without integration test file (
*.integration-spec.ts) - ❌ Controller without integration test
- ✅ Integration tests should test against real database (testcontainers)
Testing - Web (Web only):
- ❌ Unit tests using HTTP services (should use InMemory)
- ❌ Not using builder pattern for test state
- ❌ Hardcoded test data instead of builders
- ✅ Use
StoreBuilderpattern for test setup - ✅ InMemory services for all external dependencies
Reference: src/features/create-project/core/urban-project/__tests__/_testStoreHelpers.ts
Example violation:
// BAD - hardcoded test state
it("should display sites", () => {
const store = configureStore({
preloadedState: {
sites: {
list: [{ id: "1", name: "Site 1" }],
loading: false
}
}
});
// ...
});
// GOOD - builder pattern
it("should display sites", () => {
const store = new StoreBuilder()
.withSiteData({ id: "1", name: "Site 1" })
.build();
// ...
});
Dependency Injection (HIGH - API only)
NestJS Modules:
- ❌ Not using factory pattern (
useFactory) for providers - ❌ Missing
injectarray in factory providers - ❌ Not importing required modules (SqlConnectionModule, EventPublisherModule)
- ❌ Using injection tokens for UseCases (should use direct injection of
RealEventPublisher) - ✅ UseCases should inject
RealEventPublisherdirectly, not via token
Gateway Pattern (HIGH)
Gateway Pattern - API (API only):
See Controller Pattern section for API gateway checks.
Gateway Pattern - Web (Web only):
- ❌ HTTP services without InMemory mock implementation
- ❌ HTTP services not validating DTOs with Zod
safeParse() - ❌ Services not registered in store's
extraArgument - ❌ Thunks not accessing services via
extraparameter - ✅ HTTP implementation + InMemory mock required
- ✅ Validate request/response with shared Zod schemas
Reference: src/features/onboarding/infrastructure/create-user-service/HttpCreateUserService.ts
Example violation:
// BAD - no DTO validation
async createUser(data: CreateUserDto) {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify(data) // ❌ No validation
});
return response.json(); // ❌ No validation
}
// GOOD - Zod validation
import { createUserDtoSchema, createUserResponseSchema } from "shared";
async createUser(data: CreateUserDto) {
const validated = createUserDtoSchema.safeParse(data);
if (!validated.success) throw new Error("Invalid request");
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify(validated.data)
});
const json = await response.json();
const result = createUserResponseSchema.safeParse(json);
if (!result.success) throw new Error("Invalid response");
return result.data;
}
Naming Conventions (HIGH)
Naming Conventions - API (API only):
File Naming:
- ❌ UseCase files not following
[verb][Noun].usecase.tspattern - ❌ Repository files not following
Sql[Name]Repository.tspattern - ❌ Query files not following
Sql[Name]Query.tspattern - ❌ Test files not matching source file name with
.spec.tsor.integration-spec.ts
Import Aliases:
- ❌ Using relative imports (
../../../) for cross-module (should use@/) - ❌ Using
@/for shared package (should use"shared") - ❌ Long import chains when path alias would be clearer
Naming Conventions - Web (Web only):
Actions:
- ❌ Actions using imperative tense (
completeStep,fetchData) - ✅ Actions in passive tense (
stepCompleted,dataFetched)
Selectors:
- ❌ Selectors not following
select{Feature}ViewDatapattern - ✅ One ViewData selector per container component
Reducers:
- ❌ Using
createSlicein new code (legacy - maintenance only) - ✅ Use
createReducerfor new reducers
Import Aliases:
- ❌ Using relative imports (
../../../) for cross-feature imports (should use@/) - ❌ Using
@/for shared package (should use"shared") - ✅ Use
@/for imports within web app - ✅ Use
"shared"for shared package imports - ✅ Use relative
./or../only within same feature folder
Example violations:
// BAD - relative import for cross-feature
import { selectUserData } from "../../../user/core/user.selectors";
// GOOD - use @/ alias
import { selectUserData } from "@/features/user/core/user.selectors";
// BAD - using @/ for shared package
import type { Site } from "@/shared";
// GOOD - use "shared" for package imports
import type { Site } from "shared";
TypeScript & Node.js Compatibility (CRITICAL)
Erasable Types:
- ❌ TypeScript
enumusage (use Zodz.enum()or const object instead) - ❌ Namespace declarations
- ⚠️ Class parameter properties in new code (legacy allowed, but avoid in new code)
- ✅ Use
typeoverinterfaceunless extending - ✅ Use Zod schemas for enum-like types
Type Safety:
- ❌ Using
anytype (useunknownwhen type is truly unknown) - ❌ Missing explicit return types on public functions/methods
- ❌ Not using
import type { }for type-only imports - ✅
strict: truecompliance
Code Quality (HIGH)
Function/File Size:
- Large functions (>50 lines) - consider breaking down
- Large files (>800 lines) - consider splitting by responsibility
- Deep nesting (>4 levels) - refactor for readability
Error Handling:
- Missing error handling in async operations
-
console.logstatements left in production code (use proper logging) - Swallowing errors without logging
State Management:
- Mutation of shared state
- Missing immutability in domain models
Performance (MEDIUM)
- Inefficient algorithms (O(n²) when O(n log n) possible)
- N+1 query patterns (should use joins or batch queries)
- Missing database indexes on frequently queried columns
- Unnecessary re-renders in React
- Missing memoization opportunities in React
- Large bundle size additions
Best Practices (MEDIUM)
- TODO/FIXME without tickets or context
- Missing JSDoc for complex public APIs
- Poor variable naming (x, tmp, data, result without context)
- Magic numbers without explanation
- Inconsistent formatting (should run
pnpm format)
3. Confidence-Based Filtering
Only report issues you are highly confident about:
-
✅ HIGH Confidence - Clear violations visible in the diff:
- Missing
@UseGuards(JwtAuthGuard)on route -
core/importing fromadapters/ - UseCase not returning
TResult<> - TypeScript
enumusage - Missing table type after migration
- Missing
-
⚠️ MEDIUM Confidence - Probable but needs context:
- Report with caveat: "Possible issue (verify context)..."
- Large functions/files (may be justified)
- Missing tests (may exist elsewhere)
-
❌ LOW Confidence - Skip reporting:
- Require deep codebase knowledge
- May have valid reasons not visible in diff
- Speculative or style-only concerns
When in doubt, skip the issue - focus on clear, actionable problems.
4. Output Format
For each issue found, use this format:
[SEVERITY] Issue Title
File: path/to/file.ts:line
Issue: Description of the problem
Fix: How to resolve it
// Bad
<code snippet showing the problem>
// Good
<code snippet showing the fix>
Severity Levels:
- CRITICAL: Security, architecture violations, type safety issues
- HIGH: Missing tests, pattern violations, significant bugs
- MEDIUM: Performance, maintainability, code quality
- LOW: Style, minor improvements
5. ADR Check
After reviewing code quality, evaluate whether the changes involve an architectural decision worth documenting:
- New pattern or abstraction introduced
- New library or tool adopted
- Convention established that future code should follow
- Significant structural change
If any of these apply, add a note at the end of the review:
💡 **ADR suggestion**: These changes introduce [brief description]. Consider running `/adr` to document this architectural decision.
If changes follow existing patterns, skip this section silently.
6. Summary
End with a summary:
## Review Summary
- Critical: X issues
- High: X issues
- Medium: X issues
- Low: X issues
## Verdict
- ✅ APPROVE: No Critical or High issues
- ⚠️ CAUTION: Medium issues only (can proceed with awareness)
- ❌ BLOCK: Critical or High issues must be fixed
Scope
$ARGUMENTS
If no scope provided, review all uncommitted changes.
Important Notes
- Focus on high-confidence issues only - don't report speculative concerns
- Prioritize architecture violations:
- API: Clean Architecture, Result pattern, CQS
- Web: Clean Architecture, Redux patterns, Container/Presentational separation
- Check security (authentication, SQL injection, input validation)
- Verify testing:
- API: InMemory implementations, unit + integration tests
- Web: Builder pattern, InMemory services
- Validate naming:
- API: Files, database columns, imports
- Web: Actions (passive tense), selectors (ViewData), imports
- Ensure type safety (no enums, no
any, proper Result usage for API) - Check established patterns:
- Web: Redux is ESTABLISHED - no refactoring to Zustand/Jotai/MobX
-
Web: Use
createReducerfor new code, notcreateSlice
- Be concise but actionable - provide clear fixes with code examples
chat Comments (0)
Sign in to join the discussion and leave a comment.
Skill Details
Related Skills
Build your own?
Join 12,000+ developers contributing to the Claude ecosystem.
No comments yet. Be the first to share your thoughts!