# AGENTS.md - Coding Agent Guidelines

Bu dosya, bu repoda çalışan AI kodlama ajanları için rehberdir.

---

## 1. Build / Lint / Test Commands

```bash
# Development
npm run start:dev          # Dev server with watch mode
npm run build              # Production build (nest build)

# Linting & Formatting
npm run lint               # ESLint with Prettier
npm run format             # Prettier write

# Testing
npm run test                      # Run all unit tests
npm run test:watch                # Watch mode
npm run test:e2e                  # End-to-end tests
npx jest src/path/to/file.spec.ts # Run single test file
npx jest --testNamePattern="test name" # Run specific test

# Database
npx prisma generate        # Generate Prisma client (required after install)
npx prisma migrate dev     # Run migrations
npx prisma db seed         # Seed database

# Feeder Scripts
npm run feeder:historical  # Historical data fetch
npm run feeder:live        # Live match data fetch
npm run feeder:basketball  # Basketball data fetch
```

---

## 2. Code Style Guidelines

### Imports (Sıralama)

```typescript
// 1. NestJS/common imports
import { Controller, Get, Post, Body } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';

// 2. External packages
import { plainToInstance } from 'class-transformer';
import * as bcrypt from 'bcrypt';

// 3. Local imports (relative)
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/user.dto';
import { ApiResponse, createSuccessResponse } from '../../common/types';
```

### Formatting

- **Single quotes** for strings
- **Trailing commas** always
- Prettier ile formatlama zorunlu
- Dosya sonu boş satır

### Types & Type Safety

- `strictNullChecks: true` - null/undefined kontrolü zorunlu
- `noImplicitAny: false` - any kullanımına izin var (Prisma dynamic access için)
- Fonksiyon return type belirt: `async findOne(id: string): Promise<User>`
- Interface > Type alias (objeler için)

### Naming Conventions

```typescript
// Classes & Interfaces: PascalCase
class UsersService {}
interface ApiResponse<T> {}

// Variables & Functions: camelCase
const userService = new UsersService();
async function findUserById() {}

// Constants: UPPER_SNAKE_CASE
const JWT_SECRET = 'secret';
const IS_PUBLIC_KEY = 'isPublic';

// Files: kebab-case
user.dto.ts;
users.service.ts;
predictions.processor.spec.ts;

// DTOs: Entity + Dto suffix
(CreateUserDto, UpdateUserDto, UserResponseDto);
```

---

## 3. DTO Pattern

### Request DTOs

```typescript
export class CreateUserDto {
  @ApiPropertyOptional({ example: 'user@example.com' })
  @IsEmail()
  email: string;

  @IsString()
  @MinLength(8)
  password: string;

  @IsOptional()
  @IsString()
  firstName?: string;
}
```

### Response DTOs (Security Critical)

```typescript
@Exclude()
export class UserResponseDto {
  @Expose()
  id: string;

  @Expose()
  email: string;

  // passwordHash intentionally NOT exposed
}
```

### Controller Usage

```typescript
@Get('me')
async getMe(@CurrentUser() user: User): Promise<ApiResponse<UserResponseDto>> {
  const fullUser = await this.usersService.findOneWithDetails(user.id);
  return createSuccessResponse(
    plainToInstance(UserResponseDto, fullUser),
  );
}
```

**KRITIK:** Asla raw Prisma entity döndürme. Her zaman Response DTO kullan.

---

## 4. Architecture Patterns

### Service Layer

```typescript
@Injectable()
export class UsersService extends BaseService<
  User,
  CreateUserDto,
  UpdateUserDto
> {
  constructor(prisma: PrismaService) {
    super(prisma, 'User');
  }

  // Custom methods...
}
```

### Controller Layer

```typescript
@ApiTags('Users')
@ApiBearerAuth()
@Controller('users')
export class UsersController extends BaseController<
  User,
  CreateUserDto,
  UpdateUserDto
> {
  constructor(private readonly usersService: UsersService) {
    super(usersService, 'User');
  }
}
```

### API Response Format

```typescript
// All responses use this structure
{
  "success": true,
  "status": 200,
  "message": "Success",
  "data": { ... },
  "errors": []
}

// Helper functions
createSuccessResponse(data, 'Message')
createErrorResponse('Message', 400, ['error1'])
createPaginatedResponse(items, total, page, limit)
```

---

## 5. Error Handling

### Throw NestJS HTTP Exceptions

```typescript
// Correct
throw new NotFoundException('User not found');
throw new ConflictException('EMAIL_ALREADY_EXISTS');
throw new UnauthorizedException('INVALID_CREDENTIALS');

// Wrong
throw new Error('User not found'); // Don't use generic Error
```

### i18n Error Keys

```typescript
// Use translatable keys (check src/i18n/{lang}/errors.json)
throw new ConflictException('EMAIL_ALREADY_EXISTS');
// Translates to: "Email already exists" (en) / "Email zaten kayıtlı" (tr)
```

### Global Exception Filter

- Tüm hatalar HTTP 200 ile döner (status body içinde)
- `NODE_ENV=development` ise stack trace eklenir
- Validation hataları otomatik formatlanır

---

## 6. Testing

### Unit Test Structure

```typescript
import { Test, TestingModule } from '@nestjs/testing';

describe('UsersService', () => {
  let service: UsersService;
  let prisma: PrismaService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UsersService,
        { provide: PrismaService, useValue: mockPrisma },
      ],
    }).compile();

    service = module.get<UsersService>(UsersService);
  });

  it('should find user by id', async () => {
    // Arrange
    mockPrisma.user.findUnique.mockResolvedValue(mockUser);

    // Act
    const result = await service.findOne('id');

    // Assert
    expect(result).toEqual(mockUser);
  });
});
```

### Mocking External Dependencies

```typescript
jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;

beforeEach(() => {
  jest.clearAllMocks();
  mockedAxios.post.mockResolvedValue({ data: { ok: true } });
});
```

---

## 7. Module Registration

Redis-enabled modüller için `app.module.ts`:

```typescript
const redisEnabled = process.env.REDIS_ENABLED === 'true';

@Module({
  imports: [
    ...(redisEnabled ? [QueueModule, PredictionsModule] : []),
    // ...
  ],
})
```

---

## 8. Environment Variables

Zorunlu (`.env`):

```env
NODE_ENV=development
PORT=3005
DATABASE_URL=postgresql://postgres:password@localhost:15432/boilerplate_db
JWT_SECRET=your-secret-key
JWT_ACCESS_EXPIRATION=15m
REDIS_ENABLED=false
AI_ENGINE_URL=http://127.0.0.1:8000
```

---

## 9. Pre-commit Checklist

1. `npm run lint` - Lint errors fixed
2. `npm run build` - Build succeeds
3. `npm run test` - All tests pass
4. Response DTOs used for all API responses
5. No secrets/credentials in code
