Fahri Can Seçer 053f58c9b5
All checks were successful
Backend Deploy 🚀 / build-and-deploy (push) Successful in 2m35s
Update deploy.md
2026-01-27 01:31:49 +03:00
2026-01-26 23:22:38 +03:00
2026-01-27 00:17:11 +03:00
2026-01-26 23:22:38 +03:00
2026-01-27 01:31:49 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-27 00:17:11 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00
2026-01-26 23:22:38 +03:00

🚀 Enterprise NestJS Boilerplate (Antigravity Edition)

NestJS TypeScript Prisma PostgreSQL Docker

FOR AI AGENTS & DEVELOPERS: This documentation is structured to provide deep context, architectural decisions, and operational details to ensure seamless handover to any AI coding assistant (like Antigravity) or human developer.


🧠 Project Context & Architecture (Read Me First)

This is an opinionated, production-ready backend boilerplate built with NestJS. It is designed to be scalable, type-safe, and fully localized.

🏗️ Core Philosophy

  • Type Safety First: Strict TypeScript configuration. any is forbidden. DTOs are the source of truth.
  • Generic Abstraction: BaseService and BaseController handle 80% of CRUD operations, allowing developers to focus on business logic.
  • i18nNative: Localization is not an afterthought. It is baked into the exception filters, response interceptors, and guards.
  • Security by Default: JWT Auth, RBAC (Role-Based Access Control), Throttling, and Helmet are pre-configured.

📐 Architectural Decision Records (ADR)

To understand WHY things are the way they are:

  1. Handling i18n Assets:

    • Problem: Translation JSON files are not TypeScript code, so tsc ignores them during build.
    • Solution: We configured nest-cli.json with "assets": ["i18n/**/*"]. This ensures src/i18n is copied to dist/i18n automatically.
    • Note: When running with node, ensure dist/main.js can find these files.
  2. Global Response Wrapping:

    • Mechanism: ResponseInterceptor wraps all successful responses.
    • Feature: It automatically translates the "Operation successful" message based on the Accept-Language header using I18nService.
    • Output Format:
      {
        "success": true,
        "status": 200,
        "message": "İşlem başarıyla tamamlandı", // Translated
        "data": { ... }
      }
      
  3. Centralized Error Handling:

    • Mechanism: GlobalExceptionFilter catches all HttpException and unknown Error types.
    • Feature: It accepts error keys (e.g., AUTH_REQUIRED) and translates them using i18n. If a translation is found in errors.json, it is returned; otherwise, the original message is shown.
  4. UUID Generation:

    • Decision: We use Node.js native crypto.randomUUID() instead of the external uuid package to avoid CommonJS/ESM compatibility issues.

🚀 Quick Start for AI & Humans

1. Prerequisites

  • Node.js: v20.19+ (LTS)
  • Docker: For running PostgreSQL and Redis effortlessly.
  • Package Manager: npm (Lockfile: package-lock.json)

2. Environment Setup

cp .env.example .env
# ⚠️ CRITICAL: Ensure DATABASE_URL includes the username!
# Example: postgresql://postgres:password@localhost:5432/boilerplate_db

3. Installation & Database

# Install dependencies
npm ci

# Start Infrastructure (Postgres + Redis)
docker-compose up -d postgres redis

# Generate Prisma Client (REQUIRED after install)
npx prisma generate

# Run Migrations
npx prisma migrate dev

# Seed Database (Optional - Creates Admin & Roles)
npx prisma db seed

4. Running the App

# Debug Mode (Watch) - Best for Development
npm run start:dev

# Production Build & Run
npm run build
npm run start:prod

🛡️ Response Standardization & Type Safety Protocol

This boilerplate enforces a strict "No-Leak" policy for API responses to ensure both Security and Developer Experience.

1. The unknown Type is Forbidden

  • Rule: Controllers must NEVER return ApiResponse<unknown> or raw Prisma entities.
  • Why: Returning raw entities risks exposing sensitive fields like password hashes or internal metadata. It also breaks contract visibility for frontend developers.

2. DTO Pattern & Serialization

  • Tool: We use class-transformer for all response serialization.
  • Implementation:
    • All Response DTOs must use @Exclude() class-level decorator.
    • Only fields explicitly marked with @Expose() are returned to the client.
    • Controllers use plainToInstance(UserResponseDto, data) before returning data.

Example:

// ✅ Good: Secure & Typed
@Get('me')
async getMe(@CurrentUser() user: User): Promise<ApiResponse<UserResponseDto>> {
  return createSuccessResponse(plainToInstance(UserResponseDto, user));
}

// ❌ Bad: Leaks password hash & Weak Types
@Get('me')
async getMe(@CurrentUser() user: User) {
  return createSuccessResponse(user);
}

High-Performance Caching (Redis Strategy)

To ensure enterprise-grade performance, we utilize Redis for caching frequently accessed data (e.g., Roles, Permissions).

  • Library: @nestjs/cache-manager with cache-manager-redis-yet (Supports Redis v6+ / v7).
  • Configuration: Global Cache Module in AppModule.
  • Strategy: Read-heavy endpoints use @UseInterceptors(CacheInterceptor).
  • Invalidation: Write operations (Create/Update/Delete) manually invalidate relevant cache keys.

Usage:

// 1. Automatic Caching
@Get('roles')
@UseInterceptors(CacheInterceptor)
@CacheKey('roles_list') // Unique Key
@CacheTTL(60000)        // 60 Seconds
async getAllRoles() { ... }

// 2. Manual Invalidation (Inject CACHE_MANAGER)
async createRole(...) {
  // ... create role logic
  await this.cacheManager.del('roles_list'); // Clear cache
}

🤖 Gemini AI Integration (Optional)

This boilerplate includes an optional AI module powered by Google's Gemini API. It's disabled by default and can be enabled during CLI setup or manually.

Configuration

Add these to your .env file:

# Enable Gemini AI features
ENABLE_GEMINI=true

# Your Google API Key (get from https://aistudio.google.com/apikey)
GOOGLE_API_KEY=your-api-key-here

# Model to use (optional, defaults to gemini-2.5-flash)
GEMINI_MODEL=gemini-2.5-flash

Usage

The GeminiService is globally available when enabled:

import { GeminiService } from './modules/gemini';

@Injectable()
export class MyService {
  constructor(private readonly gemini: GeminiService) {}

  async generateContent() {
    // Check if Gemini is available
    if (!this.gemini.isAvailable()) {
      throw new Error('AI features are not enabled');
    }

    // 1. Simple Text Generation
    const { text, usage } = await this.gemini.generateText(
      'Write a product description for a coffee mug',
    );

    // 2. With System Prompt & Options
    const { text } = await this.gemini.generateText('Translate: Hello World', {
      systemPrompt: 'You are a professional Turkish translator',
      temperature: 0.3,
      maxTokens: 500,
    });

    // 3. Multi-turn Chat
    const { text } = await this.gemini.chat([
      { role: 'user', content: 'What is TypeScript?' },
      {
        role: 'model',
        content: 'TypeScript is a typed superset of JavaScript...',
      },
      { role: 'user', content: 'Give me an example' },
    ]);

    // 4. Structured JSON Output
    interface ProductData {
      name: string;
      price: number;
      features: string[];
    }

    const { data } = await this.gemini.generateJSON<ProductData>(
      'Generate a product entry for a wireless mouse',
      '{ name: string, price: number, features: string[] }',
    );
    console.log(data.name, data.price); // Fully typed!
  }
}

Available Methods

Method Description
isAvailable() Check if Gemini is properly configured and ready
generateText(prompt, options?) Generate text from a single prompt
chat(messages, options?) Multi-turn conversation
generateJSON<T>(prompt, schema, options?) Generate and parse structured JSON

Options

interface GeminiGenerateOptions {
  model?: string; // Override default model
  systemPrompt?: string; // System instructions
  temperature?: number; // Creativity (0-1)
  maxTokens?: number; // Max response length
}

🌍 Internationalization (i18n) Guide

Unique to this project is the deep integration of nestjs-i18n.

  • Location: src/i18n/{lang}/
  • Files:
    • common.json: Generic messages (success, welcome)
    • errors.json: Error codes (AUTH_REQUIRED, USER_NOT_FOUND)
    • validation.json: Validation messages (IS_EMAIL)
    • auth.json: Auth specific success messages (LOGIN_SUCCESS)

How to Translate a New Error:

  1. Throw an exception with a key: throw new ConflictException('EMAIL_EXISTS');
  2. Add "EMAIL_EXISTS": "Email already taken" to src/i18n/en/errors.json.
  3. Add Turkish translation to src/i18n/tr/errors.json.
  4. Start server; the GlobalExceptionFilter handles the rest.

🧪 Testing & CI/CD

  • GitHub Actions: .github/workflows/ci.yml handles build and linting checks on push.
  • Local Testing:
    npm run test        # Unit tests
    npm run test:e2e    # End-to-End tests
    

📂 System Map (Directory Structure)

src/
├── app.module.ts           # Root module (Redis, Config, i18n setup)
├── main.ts                 # Entry point
├── common/                 # Shared resources
│   ├── base/               # Abstract BaseService & BaseController (CRUD)
│   ├── types/              # Interfaces (ApiResponse, PaginatedData)
│   ├── filters/            # Global Exception Filter
│   └── interceptors/       # Response Interceptor
├── config/                 # Application configuration
├── database/               # Prisma Service
├── i18n/                   # Localization assets
└── modules/                # Feature modules
    ├── admin/              # Admin capabilities (Roles, Permissions + Caching)
    │   ├── admin.controller.ts
    │   └── dto/            # Admin Response DTOs
    ├── auth/               # Authentication layer
    ├── gemini/             # 🤖 Optional AI module (Google Gemini)
    ├── health/             # Health checks
    └── users/              # User management

🛠️ Troubleshooting (Known Issues)

1. EADDRINUSE: address already in use

  • Fix: lsof -ti:3000 | xargs kill -9

2. PrismaClientInitializationError / Database Connection Hangs

  • Fix: Check .env DATABASE_URL. Ensure docker-compose up is running.

3. Cache Manager Deprecation Warnings

  • Context: cache-manager-redis-yet may show deprecation warnings regarding Keyv. This is expected as we wait for the ecosystem to stabilize on cache-manager v6/v7. The current implementation is fully functional.

📃 License

This project is proprietary and confidential.

Description
No description provided
Readme 246 KiB
Languages
TypeScript 61.2%
Python 36.6%
JavaScript 1.1%
Dockerfile 1.1%