How to Implement Backend Patterns in ECC: A Complete Guide to Scalable Node.js Architecture

Implement backend patterns in ECC by combining repository interfaces, service layers, and middleware wrappers defined in skills/backend-patterns/SKILL.md to build secure, scalable Node.js and Next.js APIs.

Everything Claude Code (ECC) provides production-ready architectural guidelines for building server-side components in the affaan-m/ECC repository. These patterns help developers implement backend patterns in ECC projects using TypeScript, covering everything from data access abstraction to Redis caching and JWT authentication.

Core Architectural Patterns

ECC organizes backend architecture into discrete, composable layers that separate concerns and improve testability.

RESTful API Design

Start every service with clear resource-based URLs using plural, kebab-case naming and proper HTTP verbs. According to skills/backend-patterns/SKILL.md, ECC demonstrates standard CRUD routes for resources like markets with query-parameter conventions for filtering, sorting, and pagination.

Repository Pattern for Data Access

Define a technology-agnostic interface such as MarketRepository that declares data-layer operations (find, create, update, delete). Concrete implementations like SupabaseMarketRepository encapsulate storage-specific logic while keeping business logic decoupled from database vendors.

Service Layer Implementation

Business rules live in service classes like MarketService that consume repository interfaces. This layer handles complex operations such as vector search, embedding generation, and result sorting, ensuring controllers remain thin and focused on HTTP concerns.

Middleware for Cross-Cutting Concerns

Wrap API handlers with reusable middleware functions such as withAuth to enforce authentication, attach request-scoped data, and handle errors uniformly before they reach route handlers.

Database Optimization Patterns

ECC provides specific guidance for efficient database interactions that prevent common performance anti-patterns.

Selective Column Queries

Avoid SELECT * queries by specifying only required columns. The pattern uses syntax like select('id, name, status, volume') to minimize data transfer and memory overhead.

N+1 Query Prevention

Batch fetch related entities and map them back to parent objects in a single round-trip. This pattern eliminates the typical ORM performance issue where iterating over collections triggers individual database queries.

Transaction Management

Use Supabase RPC calls or raw SQL BEGIN ... COMMIT blocks to ensure atomic operations. The transaction pattern ensures that multi-step operations complete entirely or roll back without leaving partial data modifications.

Caching and Performance Strategies

Implementing backend patterns in ECC includes robust caching layers to reduce database load and improve response times.

Cache-Aside Pattern with Redis

Create a decorator class CachedMarketRepository that wraps a base repository implementation. This pattern checks the Redis cache before querying the database and populates the cache on misses with a configurable TTL.

// src/lib/repositories/cachedMarketRepository.ts
import { MarketRepository } from '@/lib/repositories';
import { RedisClient } from '@/lib/redis';

export class CachedMarketRepository implements MarketRepository {
  constructor(
    private baseRepo: MarketRepository,
    private redis: RedisClient
  ) {}

  async findById(id: string) {
    const cached = await this.redis.get(`market:${id}`);
    if (cached) return JSON.parse(cached);

    const market = await this.baseRepo.findById(id);
    if (market) {
      await this.redis.setex(`market:${id}`, 300, JSON.stringify(market));
    }
    return market;
  }
}

Explicit Cache Functions

For simpler use cases, implement helper functions like getMarketWithCache that centralize cache logic and TTL management without requiring full repository decoration.

Error Handling and Resilience

ECC emphasizes centralized error management to ensure consistent API responses across all endpoints.

Centralized Error Handling

Implement an errorHandler function that distinguishes between application errors (ApiError), validation errors (ZodError), and unexpected failures. Controllers wrap logic in try/catch blocks and delegate to this handler for standardized JSON responses.

Retry Logic with Exponential Backoff

Use the fetchWithRetry utility for external API calls, implementing exponential back-off to handle transient network failures gracefully without overwhelming downstream services.

Security and Access Control

JWT Authentication

Validate tokens using the verifyToken function, which retrieves the secret from process.env.JWT_SECRET. This pattern ensures stateless authentication for API routes.

Role-Based Access Control

Implement permission checks using higher-order functions like hasPermission and requirePermission. These wrappers enforce authorization logic before executing route handlers.

// src/app/api/markets/[id]/route.ts
import { DELETE as deleteHandler } from '@/lib/handlers';
import { requirePermission } from '@/lib/auth';

export const DELETE = requirePermission('delete')(deleteHandler);

Rate Limiting Strategies

Configure rate limiting using a shared store such as Redis, an API gateway, or platform-provided limiters. ECC explicitly warns against in-process counters that reset when scaling horizontally.

Background Processing and Observability

Job Queue Implementation

Process asynchronous tasks serially using the generic JobQueue<T> class. This pattern suits background operations such as search indexing, email sending, or data aggregation without blocking request threads.

Structured Logging

Emit JSON-structured logs using a Logger utility that includes request IDs, user IDs, and error stacks. This format enables efficient log aggregation and alerting in production environments.

Complete Implementation Example

Wire together the repository, service, and middleware patterns in a Next.js API route:

// src/app/api/markets/route.ts
import { NextResponse } from 'next/server';
import { withAuth } from '@/lib/middleware';
import { SupabaseMarketRepository } from '@/lib/repositories';
import { MarketService } from '@/lib/services';
import { errorHandler } from '@/lib/error';

const repo = new SupabaseMarketRepository();
const service = new MarketService(repo);

export const GET = withAuth(async (req) => {
  try {
    const markets = await service.searchMarkets(req.query.get('q') ?? '');
    return NextResponse.json({ success: true, data: markets });
  } catch (err) {
    return errorHandler(err, req);
  }
});

export const POST = withAuth(async (req) => {
  // Implementation for creating markets
});

Summary

  • Repository Pattern: Isolate data access behind interfaces like MarketRepository to swap storage implementations without affecting business logic.
  • Service Layer: Encapsulate complex operations in MarketService classes to keep controllers focused on HTTP transport.
  • Middleware: Use wrappers like withAuth and requirePermission to handle cross-cutting concerns uniformly.
  • Caching: Implement CachedMarketRepository or explicit cache functions using Redis to reduce database load.
  • Error Handling: Centralize error processing in errorHandler and use fetchWithRetry for resilient external calls.
  • Security: Combine JWT validation (verifyToken) with role-based access control (requirePermission) and shared-store rate limiting.

Frequently Asked Questions

What file contains the backend pattern definitions in ECC?

The primary documentation lives in skills/backend-patterns/SKILL.md within the affaan-m/ECC repository. A localized version for the KiRo documentation system exists at .kiro/skills/backend-patterns/SKILL.md, and Chinese translations are available at docs/zh-CN/skills/backend-patterns/SKILL.md.

How does ECC implement the cache-aside pattern?

ECC implements cache-aside through decorator classes like CachedMarketRepository that wrap base repositories. These classes check Redis first via redis.get(), return cached data if present, or query the database and populate the cache using redis.setex() with a TTL (typically 300 seconds).

What authentication mechanisms does ECC support?

ECC supports JWT token validation via verifyToken for stateless authentication and role-based access control through hasPermission and requirePermission higher-order functions. The patterns require storing JWT_SECRET in environment variables and wrapping sensitive routes with authentication middleware.

How does ECC prevent the N+1 query problem?

The repository recommends batch fetching related entities and manually mapping them back to parent objects rather than relying on ORM lazy loading. This approach retrieves all necessary data in a single query, preventing the performance degradation caused by iterative database calls within loops.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →