Files
iddaai-be/AGENTS.md
fahricansecer 7814e0bc6b
Deploy Iddaai Backend / build-and-deploy (push) Failing after 4s
first (part 1: root files)
2026-04-16 15:09:10 +03:00

323 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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