Code Review Guidelines

This document serves as a comprehensive checklist for reviewing code in the TurboStack project. It is designed to ensure code quality, consistency, security, and architectural integrity across the monorepo. Use this checklist before submitting a Pull Request (PR) or during the code review process.
These guidelines are enforced to maintain the high standards of the TurboStack architecture. Adhering to them ensures a smooth development process and a robust production environment.

🧠 General (Stack Agnostic)

Core Principles

  • Single Responsibility Principle (SRP): Does each file, function, and service perform a single, well-defined task?
  • Naming Conventions: Is the naming clear and domain-specific? (e.g., userSettings, billingCycle, subscriptionPlan instead of generic names like data, config).
  • Dead Code: Are there any unused exports, variables, or imports that should be removed?
  • Side Effects: Are side effects (especially in server actions and hooks) explicit and managed correctly?
  • Environment Variables: Are env variables handled securely? (e.g., process.env should not be leaked to the client directly; use validated config via @t3-oss/env-nextjs).
  • Magic Numbers/Strings: Are magic strings and numbers replaced with enums or constants?
  • Error Handling: Is there robust error handling, or does the code only cover the “happy path”?
  • Logging: Is the log level appropriate? (No console.log in production; use structured logging like pino).

⚛️ Frontend – Next.js (App Router)

1️⃣ Architecture & Folder Structure

  • Routing vs. Logic: Does app/ strictly handle routing and composition?
  • Business Logic Placement:
    • ❌ Business logic in page.tsx
    • ✅ Logic moved to features/, services/, or hooks/
  • Component Classification:
    • components/ui: Dumb/presentational components (shadcn/ui)
    • components/features: Domain-aware components
  • Responsibility: Page components should orchestrate; UI components should render.

2️⃣ Server / Client Boundary

  • “use client” Usage: Is "use client" minimized and used only when necessary?
  • Server Components: Ensure no client-side specific APIs (e.g., useEffect, window, localStorage) are used in Server Components.
  • Client Components: Avoid heavy data fetching directly in Client Components unless necessary.
  • Data Fetching Strategy: Fetch data on the server, manage state on the client where appropriate.

3️⃣ Data Fetching

  • Caching Strategy: Are fetch cache settings (no-store, revalidate) explicitly defined?
  • Service Layer:
    • ❌ Fetching the same endpoint in multiple places
    • ✅ Using a unified service layer (apps/frontend/services) for API calls
  • Parallel Fetching: Are independent data fetches executed in parallel (e.g., using Promise.all)?

4️⃣ Performance

  • Re-renders: Are unnecessary re-renders avoided?
  • Memoization: Are useMemo and useCallback used effectively (not just reflexively)?
  • Large Lists: Is pagination or virtualization used for large datasets?
  • Image Optimization: Is next/image used for images?
  • Bundle Size: Are there any heavy libraries bloating the bundle?

5️⃣ Form & Validation

  • Validation Layer:
    • ❌ Validation logic only in the frontend
    • ✅ Shared Zod schemas (@repo/validations) used for both frontend and backend
  • User Feedback: Are validation errors and success states clearly communicated to the user (e.g., via sonner toast)?
  • Optimistic UI: If used, is there a rollback mechanism for failed operations?

6️⃣ DX & Maintainability

  • Reusable Hooks: Are custom hooks truly reusable and logic-focused?
    • ❌ Hook rendering UI
    • ✅ Hook managing logic only
  • Type Safety:
    • ❌ Avoid any and as unknown as
    • ✅ Ensure API responses are fully type-safe via shared types or Eden Treaty

🦊 Backend – Elysia.js

1️⃣ Route Structure

  • Logic Separation:
    • ❌ Routes containing business logic
    • ✅ Routes strictly handling HTTP request/response orchestration, delegating logic to services/
  • Layered Architecture: Is there a clear separation between Route Handlers and Services?

2️⃣ Elysia Best Practices

  • Schema Validation: Are t.Object, t.Enum, and other TypeBox schemas used for validation in routes?
  • Schema Definition: Are request/response schemas explicitly defined for Swagger documentation?
  • Shared Schemas: Are schemas shared with the frontend for consistency?
  • Schema Role: Treat schemas as validation, documentation, and type safety mechanisms.

3️⃣ Auth & Security

  • Auth Implementation:
    • ❌ Scattered auth checks in routes
    • ✅ Centralized middleware or derive usage for session injection
  • Role Checking: Is requireAdmin or similar helpers used for role-based access control?
  • Error Security:
    • ❌ Leaking database errors (e.g., “User not found in DB query”)
    • ✅ Returning standardized errors (e.g., “Unauthorized”, “Not Found”)

4️⃣ Error Handling

  • Global Handling: Is the global .onError handler used for standardizing responses?
  • Custom Errors: Are custom error types (AppError) used?
    throw new AppError("USER_NOT_FOUND", "User not found", 404);
    
  • Status Codes: Are HTTP status codes used consistently and correctly (e.g., 400 for validation, 401 for auth, 403 for permission)?

5️⃣ Database / ORM

  • N+1 Queries: Are potential N+1 query issues identified and resolved (e.g., using include correctly)?
  • Transactions: Are database transactions used where atomicity is required?
  • Pagination:
    • ❌ Fetching all records (findMany() without limits)
    • ✅ Using take, skip based on pagination params
  • Indexing: Are database indexes applied to frequently queried fields (in schema.prisma)?

6️⃣ Performance

  • Heavy Operations: Are heavy computations (e.g., image processing) handled efficiently?
  • Response Size: Is the response payload optimized (no unnecessary data)?
  • Await Chains: Are unnecessary sequential await calls avoided where Promise.all could be used?

🔗 Frontend ↔ Backend Consistency

  • Response Shape:
    • ❌ Inconsistent response formats
    • ✅ Standardized response structure (ApiResponse<T>):
      {
        success: boolean;
        data?: T;
        message?: string;
        error?: string;
      }
      
  • Shared Types: Is there a shared @repo/types or validation package used by both ends?
  • Breaking Changes: Does the type system catch breaking changes across the boundary?

🚩 Red Flags (Immediate Changes Required)

  • Effect Fetching: useEffect containing direct fetch calls without a robust strategy (use Service layer).
  • Direct DB Access: API routes accessing the database directly instead of through a service.
  • Logic in Pages: Next.js pages containing complex business logic.
  • Massive Components: Components exceeding 500 lines of code.
  • “Refactor Later”: Comments promising future refactoring (“TODO: fix later”) without immediate plans.