Optimize code for AI assistents
This commit is contained in:
parent
aa19c08292
commit
8140c86dfe
99
.cursorrules
Normal file
99
.cursorrules
Normal file
@ -0,0 +1,99 @@
|
||||
# Telegram Bot with Admin Panel Starter - Cursor Rules
|
||||
|
||||
## Project Overview
|
||||
This is a starter template for building Telegram bots with web-based admin panels.
|
||||
|
||||
**Tech Stack:**
|
||||
- Backend: NestJS 11, TypeORM, PostgreSQL, Grammy (Telegram Bot Framework)
|
||||
- Frontend: React 18, Vite, Mantine UI 7, React Query, Zod
|
||||
- Infrastructure: Docker Compose
|
||||
|
||||
## Code Style & Conventions
|
||||
|
||||
### TypeScript
|
||||
- Use strict typing - avoid `any` when possible
|
||||
- Prefer interfaces over types for object shapes
|
||||
- Use enums for fixed sets of values
|
||||
- Always define return types for functions
|
||||
- Use JSDoc comments for public APIs
|
||||
|
||||
### NestJS Backend
|
||||
- Follow NestJS module structure: Controller → Service → Repository pattern
|
||||
- Use DTOs with class-validator for all request/response validation
|
||||
- Use decorators from `@nestjs/common` consistently
|
||||
- Services should contain business logic, controllers only handle HTTP
|
||||
- Use dependency injection - avoid direct instantiation
|
||||
- Use guards for authentication/authorization
|
||||
- Use interceptors for response transformation
|
||||
- Use custom decorators for common patterns (pagination, filtering, sorting)
|
||||
|
||||
### React Frontend
|
||||
- Use functional components with hooks
|
||||
- Use React Query for all API calls
|
||||
- Use Zod schemas for type-safe API validation
|
||||
- Use Mantine components consistently
|
||||
- Create reusable hooks for common patterns
|
||||
- Use TypeScript paths (@/*) for imports
|
||||
- Keep components small and focused
|
||||
|
||||
### Database
|
||||
- Use TypeORM entities with decorators
|
||||
- All entities extend `AbstractEntity` (id, created_at, updated_at)
|
||||
- Use migrations for all schema changes
|
||||
- Never use `synchronize: true` in production
|
||||
- Use relations properly (OneToOne, OneToMany, ManyToMany)
|
||||
|
||||
### API Design
|
||||
- RESTful endpoints: GET, POST, PATCH, DELETE
|
||||
- Use consistent response format: `{ statusCode, message, data }`
|
||||
- Pagination: `page` (1-indexed) and `size` (default 25)
|
||||
- Sorting: `sortBy` and `sortOrder` (asc/desc)
|
||||
- Filtering: use `FilteringParams` decorator with filter rules (eq, neq, like, etc.)
|
||||
- Use JWT for authentication
|
||||
- Protect routes with `@UseGuards(AuthGuard)`
|
||||
|
||||
### File Naming
|
||||
- Controllers: `*.controller.ts`
|
||||
- Services: `*.service.ts`
|
||||
- Entities: `*.entity.ts`
|
||||
- DTOs: `*.dto.ts`
|
||||
- Guards: `*.guard.ts`
|
||||
- Decorators: `*.decorator.ts`
|
||||
- Modules: `*.module.ts`
|
||||
|
||||
### Git
|
||||
- Use conventional commits
|
||||
- Keep commits focused and atomic
|
||||
- Never commit `.env` files or secrets
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Creating a New Feature Module
|
||||
1. Create module folder: `back/src/feature-name/`
|
||||
2. Create entity: `entities/feature-name.entity.ts`
|
||||
3. Create DTOs: `dto/create-feature-name.dto.ts`, `dto/update-feature-name.dto.ts`
|
||||
4. Create service: `feature-name.service.ts`
|
||||
5. Create controller: `feature-name.controller.ts`
|
||||
6. Create module: `feature-name.module.ts`
|
||||
7. Register in `app.module.ts`
|
||||
8. Create migration: `pnpm migration:generate --name=create-feature-name`
|
||||
|
||||
### Adding Bot Commands
|
||||
1. Add handler method in `BotService`
|
||||
2. Register in `onModuleInit()`: `this.bot.command('command', this.handler.bind(this))`
|
||||
3. Use Grammy Context types for type safety
|
||||
|
||||
### Adding Frontend Pages
|
||||
1. Create page component in `front/src/pages/`
|
||||
2. Add route in `front/src/routes/`
|
||||
3. Create API hooks in `front/src/hooks/api/`
|
||||
4. Create Zod schemas in `front/src/api/dtos/`
|
||||
5. Use Mantine components for UI
|
||||
|
||||
## Important Notes
|
||||
- Always validate environment variables in `config/env/env.validation.ts`
|
||||
- Use `ConfigService` to access environment variables
|
||||
- Static files served from `/uploads` endpoint
|
||||
- Database migrations run automatically on container start
|
||||
- Use `pnpm` as package manager (not npm or yarn)
|
||||
- Node.js v20+ required (v22 recommended)
|
||||
267
AGENTS.md
Normal file
267
AGENTS.md
Normal file
@ -0,0 +1,267 @@
|
||||
# Architecture Guide for AI Agents
|
||||
|
||||
This document provides comprehensive architecture information to help AI assistants understand and work with this codebase effectively.
|
||||
|
||||
## System Architecture
|
||||
|
||||
### High-Level Overview
|
||||
```
|
||||
┌─────────────┐ HTTP/REST ┌─────────────┐
|
||||
│ Frontend │ ◄─────────────────► │ Backend │
|
||||
│ (React) │ │ (NestJS) │
|
||||
└─────────────┘ └──────┬──────┘
|
||||
│
|
||||
│ Grammy API
|
||||
▼
|
||||
┌─────────────┐
|
||||
│ Telegram │
|
||||
│ Bot │
|
||||
└─────────────┘
|
||||
│
|
||||
│ PostgreSQL
|
||||
▼
|
||||
┌─────────────┐
|
||||
│ Database │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
## Backend Architecture (NestJS)
|
||||
|
||||
### Module Structure
|
||||
Each feature follows NestJS module pattern:
|
||||
- **Module**: Registers providers, imports dependencies
|
||||
- **Controller**: Handles HTTP requests/responses
|
||||
- **Service**: Contains business logic
|
||||
- **Entity**: TypeORM database model
|
||||
- **DTO**: Data Transfer Objects for validation
|
||||
|
||||
### Key Modules
|
||||
|
||||
#### `AppModule` (Root Module)
|
||||
- Imports all feature modules
|
||||
- Configures global modules (Config, Database)
|
||||
- Entry point: `main.ts`
|
||||
|
||||
#### `DatabaseModule`
|
||||
- Configures TypeORM with PostgreSQL
|
||||
- Registers all entities
|
||||
- Handles migrations
|
||||
|
||||
#### `AuthModule`
|
||||
- JWT-based authentication
|
||||
- Login/Register endpoints
|
||||
- Token verification
|
||||
- Guards for route protection
|
||||
|
||||
#### `AdminsModule`
|
||||
- Admin user CRUD operations
|
||||
- Role management (superadmin/admin)
|
||||
- Pagination, sorting, filtering support
|
||||
|
||||
#### `BotModule`
|
||||
- Telegram bot integration via Grammy
|
||||
- Command handlers
|
||||
- Message sending utilities
|
||||
|
||||
#### `CommonModule`
|
||||
- Shared utilities
|
||||
- Custom decorators (pagination, filtering, sorting)
|
||||
- Base entities
|
||||
- Interceptors
|
||||
|
||||
### Request Flow
|
||||
```
|
||||
HTTP Request
|
||||
↓
|
||||
Controller (validates DTO)
|
||||
↓
|
||||
Guard (AuthGuard - checks JWT)
|
||||
↓
|
||||
Service (business logic)
|
||||
↓
|
||||
Repository/TypeORM (database)
|
||||
↓
|
||||
Response Interceptor (formats response)
|
||||
↓
|
||||
HTTP Response
|
||||
```
|
||||
|
||||
### Response Format
|
||||
All API responses follow this structure:
|
||||
```typescript
|
||||
{
|
||||
statusCode: number;
|
||||
message: string;
|
||||
data: T; // Actual response data
|
||||
}
|
||||
```
|
||||
|
||||
### Pagination
|
||||
- Query params: `page` (1-indexed), `size` (default: 25)
|
||||
- Response includes `totalCount` and `items[]`
|
||||
|
||||
### Sorting
|
||||
- Query params: `sortBy` (field name), `sortOrder` (asc/desc)
|
||||
- Controller specifies allowed fields: `@SortingParams(['id', 'created_at'])`
|
||||
|
||||
### Filtering
|
||||
- Query param: `filters[]` array
|
||||
- Format: `field:rule:value` (e.g., `username:like:john`)
|
||||
- Rules: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `like`, `nlike`, `in`, `nin`, `isnull`, `isnotnull`, `between`
|
||||
- Controller specifies allowed fields: `@FilteringParams(['username', 'role'])`
|
||||
|
||||
## Frontend Architecture (React)
|
||||
|
||||
### Structure
|
||||
```
|
||||
src/
|
||||
├── api/ # API client setup, helpers, DTOs
|
||||
├── components/ # Reusable UI components
|
||||
├── guards/ # Route guards (auth, guest)
|
||||
├── hooks/ # Custom hooks (auth, API queries)
|
||||
├── layouts/ # Page layouts (auth, dashboard)
|
||||
├── pages/ # Page components
|
||||
├── providers/ # Context providers
|
||||
├── routes/ # React Router configuration
|
||||
└── theme/ # Mantine theme customization
|
||||
```
|
||||
|
||||
### API Integration
|
||||
- Uses Axios for HTTP requests
|
||||
- React Query for data fetching/caching
|
||||
- Zod schemas for runtime validation
|
||||
- Custom hooks generated via `createGetQueryHook`, `createPostMutationHook`, etc.
|
||||
|
||||
### State Management
|
||||
- React Query for server state
|
||||
- Zustand for client state (if needed)
|
||||
- Context API for auth state
|
||||
|
||||
### Routing
|
||||
- React Router v6
|
||||
- Protected routes via guards
|
||||
- Lazy loading for code splitting
|
||||
|
||||
## Database Schema
|
||||
|
||||
### Entities
|
||||
|
||||
#### `Admin`
|
||||
- `id`: number (PK, auto-increment)
|
||||
- `username`: string (255)
|
||||
- `email`: string (255)
|
||||
- `image`: string | null
|
||||
- `is_active`: boolean (default: true)
|
||||
- `role`: enum ('superadmin' | 'admin')
|
||||
- `created_at`: Date
|
||||
- `updated_at`: Date
|
||||
- Relations: `OneToOne` with `Password`
|
||||
|
||||
#### `Password`
|
||||
- `id`: number (PK)
|
||||
- `admin_id`: number (FK)
|
||||
- `hash`: string (bcrypt hash)
|
||||
- Relations: `OneToOne` with `Admin`
|
||||
|
||||
### Abstract Entity
|
||||
All entities extend `AbstractEntity`:
|
||||
- `id`: Primary key
|
||||
- `created_at`: Creation timestamp
|
||||
- `updated_at`: Update timestamp
|
||||
|
||||
## Telegram Bot Integration
|
||||
|
||||
### Grammy Framework
|
||||
- Bot instance created in `BotService`
|
||||
- Commands registered in `onModuleInit()`
|
||||
- Context types from Grammy for type safety
|
||||
|
||||
### Common Patterns
|
||||
```typescript
|
||||
// Register command
|
||||
this.bot.command('command', this.handler.bind(this));
|
||||
|
||||
// Send message
|
||||
await this.bot.api.sendMessage(chatId, message, options);
|
||||
|
||||
// Keyboard
|
||||
const keyboard = new Keyboard().text('Button').row();
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Backend
|
||||
- `PORT`: Server port (default: 4000)
|
||||
- `JWT_SECRET`: Secret for JWT signing
|
||||
- `TELEGRAM_BOT_TOKEN`: Telegram bot token
|
||||
- `DB_HOST`: Database host
|
||||
- `DB_PORT`: Database port (default: 5432)
|
||||
- `DB_USERNAME`: Database username
|
||||
- `DB_PASSWORD`: Database password
|
||||
- `DB_NAME`: Database name
|
||||
- `NODE_ENV`: Environment (development/production)
|
||||
|
||||
### Frontend
|
||||
- `API_URL`: Backend API URL
|
||||
- `PORT`: Dev server port (default: 3000)
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Adding a New Feature
|
||||
|
||||
1. **Backend**:
|
||||
- Create entity: `back/src/feature/entities/feature.entity.ts`
|
||||
- Create DTOs: `back/src/feature/dto/*.dto.ts`
|
||||
- Create service: `back/src/feature/feature.service.ts`
|
||||
- Create controller: `back/src/feature/feature.controller.ts`
|
||||
- Create module: `back/src/feature/feature.module.ts`
|
||||
- Register in `AppModule`
|
||||
- Generate migration: `pnpm migration:generate --name=create-feature`
|
||||
|
||||
2. **Frontend**:
|
||||
- Create Zod schemas: `front/src/api/dtos/feature.ts`
|
||||
- Create API hooks: `front/src/hooks/api/feature.ts`
|
||||
- Create page component: `front/src/pages/feature/`
|
||||
- Add route: `front/src/routes/index.tsx`
|
||||
|
||||
### Testing
|
||||
- Backend: Jest (unit + e2e)
|
||||
- Frontend: Vitest + React Testing Library
|
||||
|
||||
## Common Code Patterns
|
||||
|
||||
### Backend Controller Example
|
||||
```typescript
|
||||
@Controller('resource')
|
||||
export class ResourceController {
|
||||
constructor(private readonly service: ResourceService) {}
|
||||
|
||||
@UseGuards(AuthGuard)
|
||||
@Get()
|
||||
findChunk(
|
||||
@PaginationParams() pagination: IPagination,
|
||||
@SortingParams(['id', 'name']) sorting: ISorting,
|
||||
@FilteringParams(['name', 'status']) filtering: IFiltering,
|
||||
) {
|
||||
return this.service.findChunk(pagination, sorting, filtering);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Frontend Hook Example
|
||||
```typescript
|
||||
const useGetResource = createPaginationQueryHook({
|
||||
endpoint: '/api/resource',
|
||||
dataSchema: resourceSchema,
|
||||
rQueryParams: { queryKey: ['getResource'] },
|
||||
});
|
||||
```
|
||||
|
||||
## Important Conventions
|
||||
|
||||
1. **Naming**: Use descriptive names, follow camelCase for variables, PascalCase for classes
|
||||
2. **Error Handling**: Use NestJS exceptions, handle in interceptors
|
||||
3. **Validation**: Always validate input with DTOs and class-validator
|
||||
4. **Type Safety**: Use TypeScript strictly, avoid `any`
|
||||
5. **Comments**: Add JSDoc for public APIs
|
||||
6. **Security**: Never expose secrets, validate all inputs, use guards
|
||||
137
AI_ENHANCEMENTS.md
Normal file
137
AI_ENHANCEMENTS.md
Normal file
@ -0,0 +1,137 @@
|
||||
# AI-Friendly Enhancements
|
||||
|
||||
This document summarizes all improvements made to optimize the project for LLM-assisted development.
|
||||
|
||||
## Created Files
|
||||
|
||||
### 1. `.cursorrules`
|
||||
**Purpose**: Provides Cursor AI with project conventions and patterns
|
||||
**Contains**:
|
||||
- Code style guidelines
|
||||
- Common patterns for NestJS and React
|
||||
- File naming conventions
|
||||
- Git workflow rules
|
||||
|
||||
### 2. `AGENTS.md`
|
||||
**Purpose**: Comprehensive architecture documentation for AI assistants
|
||||
**Contains**:
|
||||
- System architecture diagrams
|
||||
- Module structure explanations
|
||||
- Request/response flow
|
||||
- Database schema documentation
|
||||
- Development workflow guides
|
||||
|
||||
### 3. `EXAMPLES.md`
|
||||
**Purpose**: Practical code examples and usage patterns
|
||||
**Contains**:
|
||||
- API endpoint examples
|
||||
- Frontend hook usage
|
||||
- Telegram bot command examples
|
||||
- Database migration examples
|
||||
- Environment setup guide
|
||||
|
||||
### 4. `CONTRIBUTING.md`
|
||||
**Purpose**: Guide for contributors (human and AI)
|
||||
**Contains**:
|
||||
- Development setup instructions
|
||||
- Code style guidelines
|
||||
- Feature addition workflow
|
||||
- Git workflow
|
||||
- Testing instructions
|
||||
|
||||
### 5. `back/src/common/types/api.types.ts`
|
||||
**Purpose**: TypeScript type definitions for API responses
|
||||
**Contains**:
|
||||
- `ApiResponse<T>` interface
|
||||
- `PaginatedResponse<T>` interface
|
||||
- JSDoc documentation
|
||||
|
||||
## Enhanced Files
|
||||
|
||||
### 1. `README.md`
|
||||
**Added**: Section "🤖 Development with AI Assistants"
|
||||
- Quick reference to AI documentation files
|
||||
- Common tasks guide
|
||||
- Links to relevant documentation
|
||||
|
||||
### 2. `.env.example`
|
||||
**Enhanced**: Added detailed comments for all environment variables
|
||||
- Explanations for each variable
|
||||
- Generation instructions for secrets
|
||||
- Format examples
|
||||
|
||||
### 3. `back/src/bot/bot.service.ts`
|
||||
**Added**: Comprehensive JSDoc comments
|
||||
- Class-level documentation
|
||||
- Method documentation with examples
|
||||
- Parameter descriptions
|
||||
|
||||
### 4. `back/src/common/decorators/filtering-params.decorator.ts`
|
||||
**Added**: Detailed JSDoc comments
|
||||
- Enum documentation
|
||||
- Function documentation
|
||||
- Usage examples
|
||||
|
||||
### 5. `back/src/common/decorators/pagination-params.decorator.ts`
|
||||
**Added**: JSDoc comments
|
||||
- Interface documentation
|
||||
- Decorator usage examples
|
||||
|
||||
### 6. `back/src/common/decorators/sorting-params.decorator.ts`
|
||||
**Added**: JSDoc comments
|
||||
- Interface documentation
|
||||
- Decorator usage examples
|
||||
|
||||
### 7. `back/src/app.module.ts`
|
||||
**Added**: Module-level JSDoc comment
|
||||
- Description of module purpose
|
||||
- List of imported modules
|
||||
|
||||
### 8. `back/src/common/entities/abstract.entity.ts`
|
||||
**Added**: Class-level JSDoc comment
|
||||
- Explanation of base entity purpose
|
||||
- Usage example
|
||||
|
||||
## Benefits for AI Development
|
||||
|
||||
1. **Better Context Understanding**
|
||||
- AI assistants can quickly understand project structure
|
||||
- Clear patterns and conventions reduce ambiguity
|
||||
- Architecture documentation provides system overview
|
||||
|
||||
2. **Consistent Code Generation**
|
||||
- `.cursorrules` ensures AI follows project conventions
|
||||
- Examples show exact patterns to use
|
||||
- Type definitions provide clear interfaces
|
||||
|
||||
3. **Faster Development**
|
||||
- AI can reference examples instead of guessing
|
||||
- Common patterns are documented
|
||||
- Workflow guides reduce trial and error
|
||||
|
||||
4. **Better Code Quality**
|
||||
- JSDoc comments help AI understand intent
|
||||
- Type definitions prevent errors
|
||||
- Examples show best practices
|
||||
|
||||
## Usage Tips
|
||||
|
||||
### For Developers
|
||||
- Read `.cursorrules` to understand project conventions
|
||||
- Check `AGENTS.md` when adding new features
|
||||
- Reference `EXAMPLES.md` for implementation patterns
|
||||
|
||||
### For AI Assistants
|
||||
- Start by reading `.cursorrules` for code style
|
||||
- Check `AGENTS.md` for architecture understanding
|
||||
- Use `EXAMPLES.md` for code generation patterns
|
||||
- Reference type definitions in `back/src/common/types/`
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Consider adding:
|
||||
- [ ] OpenAPI/Swagger documentation
|
||||
- [ ] More detailed test examples
|
||||
- [ ] Performance optimization guides
|
||||
- [ ] Deployment documentation
|
||||
- [ ] Troubleshooting guide
|
||||
201
CONTRIBUTING.md
Normal file
201
CONTRIBUTING.md
Normal file
@ -0,0 +1,201 @@
|
||||
# Contributing Guide
|
||||
|
||||
This guide helps developers (and AI assistants) understand how to contribute to this project.
|
||||
|
||||
## Development Setup
|
||||
|
||||
1. **Clone the repository**
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd bot-with-admin-starter
|
||||
```
|
||||
|
||||
2. **Set up environment**
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env with your values
|
||||
```
|
||||
|
||||
3. **Start development environment**
|
||||
```bash
|
||||
docker compose -f compose.dev.yml up -d
|
||||
```
|
||||
|
||||
4. **Create super admin**
|
||||
```bash
|
||||
docker exec -it ${PROJECT_NAME}_back sh
|
||||
pnpm console admin create {username} {email}
|
||||
```
|
||||
|
||||
5. **Start frontend**
|
||||
```bash
|
||||
cd front
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
### TypeScript
|
||||
- Use strict typing - avoid `any`
|
||||
- Prefer interfaces over types
|
||||
- Use enums for fixed sets
|
||||
- Always define return types
|
||||
- Add JSDoc for public APIs
|
||||
|
||||
### NestJS Backend
|
||||
- Follow module structure: Controller → Service → Repository
|
||||
- Use DTOs with class-validator
|
||||
- Services contain business logic, controllers handle HTTP
|
||||
- Use dependency injection
|
||||
- Use guards for auth
|
||||
- Use interceptors for response transformation
|
||||
|
||||
### React Frontend
|
||||
- Functional components with hooks
|
||||
- React Query for API calls
|
||||
- Zod schemas for validation
|
||||
- Mantine components consistently
|
||||
- TypeScript paths (@/*) for imports
|
||||
|
||||
## Adding a New Feature
|
||||
|
||||
### Backend
|
||||
|
||||
1. **Create entity**
|
||||
```bash
|
||||
# File: back/src/feature/entities/feature.entity.ts
|
||||
```
|
||||
```typescript
|
||||
import { Entity, Column } from 'typeorm';
|
||||
import { AbstractEntity } from 'src/common/entities/abstract.entity';
|
||||
|
||||
@Entity('features')
|
||||
export class Feature extends AbstractEntity {
|
||||
@Column()
|
||||
name: string;
|
||||
}
|
||||
```
|
||||
|
||||
2. **Create DTOs**
|
||||
```bash
|
||||
# Files: back/src/feature/dto/create-feature.dto.ts
|
||||
# back/src/feature/dto/update-feature.dto.ts
|
||||
```
|
||||
|
||||
3. **Create service**
|
||||
```bash
|
||||
# File: back/src/feature/feature.service.ts
|
||||
```
|
||||
|
||||
4. **Create controller**
|
||||
```bash
|
||||
# File: back/src/feature/feature.controller.ts
|
||||
```
|
||||
|
||||
5. **Create module**
|
||||
```bash
|
||||
# File: back/src/feature/feature.module.ts
|
||||
```
|
||||
|
||||
6. **Register in AppModule**
|
||||
```typescript
|
||||
// back/src/app.module.ts
|
||||
imports: [
|
||||
// ...
|
||||
FeatureModule,
|
||||
]
|
||||
```
|
||||
|
||||
7. **Generate migration**
|
||||
```bash
|
||||
cd back
|
||||
pnpm migration:generate --name=create-feature
|
||||
```
|
||||
|
||||
### Frontend
|
||||
|
||||
1. **Create Zod schemas**
|
||||
```bash
|
||||
# File: front/src/api/dtos/feature.ts
|
||||
```
|
||||
|
||||
2. **Create API hooks**
|
||||
```bash
|
||||
# File: front/src/hooks/api/feature.ts
|
||||
```
|
||||
|
||||
3. **Create page component**
|
||||
```bash
|
||||
# File: front/src/pages/feature/index.tsx
|
||||
```
|
||||
|
||||
4. **Add route**
|
||||
```typescript
|
||||
// front/src/routes/index.tsx
|
||||
{
|
||||
path: '/feature',
|
||||
element: <FeaturePage />,
|
||||
}
|
||||
```
|
||||
|
||||
## Git Workflow
|
||||
|
||||
1. **Create feature branch**
|
||||
```bash
|
||||
git checkout -b feature/my-feature
|
||||
```
|
||||
|
||||
2. **Make changes**
|
||||
- Write code following style guide
|
||||
- Add tests if applicable
|
||||
- Update documentation
|
||||
|
||||
3. **Commit changes**
|
||||
```bash
|
||||
git commit -m "feat: add new feature"
|
||||
```
|
||||
Use conventional commits:
|
||||
- `feat:` New feature
|
||||
- `fix:` Bug fix
|
||||
- `docs:` Documentation
|
||||
- `style:` Formatting
|
||||
- `refactor:` Code refactoring
|
||||
- `test:` Tests
|
||||
- `chore:` Maintenance
|
||||
|
||||
4. **Push and create PR**
|
||||
```bash
|
||||
git push origin feature/my-feature
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Backend
|
||||
```bash
|
||||
cd back
|
||||
pnpm test
|
||||
pnpm test:e2e
|
||||
```
|
||||
|
||||
### Frontend
|
||||
```bash
|
||||
cd front
|
||||
npm run test
|
||||
```
|
||||
|
||||
## Code Review Checklist
|
||||
|
||||
- [ ] Code follows style guide
|
||||
- [ ] Tests pass
|
||||
- [ ] Documentation updated
|
||||
- [ ] No console.logs or debug code
|
||||
- [ ] Environment variables documented
|
||||
- [ ] Migration files created for schema changes
|
||||
- [ ] JSDoc comments added for public APIs
|
||||
|
||||
## Questions?
|
||||
|
||||
- Check `.cursorrules` for code conventions
|
||||
- See `AGENTS.md` for architecture details
|
||||
- See `EXAMPLES.md` for code examples
|
||||
327
EXAMPLES.md
Normal file
327
EXAMPLES.md
Normal file
@ -0,0 +1,327 @@
|
||||
# API Usage Examples
|
||||
|
||||
This document provides practical examples for using the API endpoints and common patterns.
|
||||
|
||||
## Authentication
|
||||
|
||||
### Login
|
||||
```typescript
|
||||
// Backend endpoint: POST /auth/login
|
||||
// Request body:
|
||||
{
|
||||
"email": "admin@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
|
||||
// Response:
|
||||
{
|
||||
"statusCode": 200,
|
||||
"message": "Login successful",
|
||||
"data": {
|
||||
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Register (requires authentication)
|
||||
```typescript
|
||||
// Backend endpoint: POST /auth/register
|
||||
// Headers: Authorization: Bearer <token>
|
||||
// Request body:
|
||||
{
|
||||
"username": "newadmin",
|
||||
"email": "newadmin@example.com",
|
||||
"password": "securepassword",
|
||||
"role": "admin" // or "superadmin"
|
||||
}
|
||||
```
|
||||
|
||||
### Verify Token
|
||||
```typescript
|
||||
// Backend endpoint: GET /auth/verify-token
|
||||
// Headers: Authorization: Bearer <token>
|
||||
// Response: Admin object
|
||||
```
|
||||
|
||||
## Admins CRUD
|
||||
|
||||
### Get All Admins (Paginated)
|
||||
```typescript
|
||||
// Backend endpoint: GET /admins
|
||||
// Query params:
|
||||
// page=1
|
||||
// size=25
|
||||
// sortBy=created_at
|
||||
// sortOrder=desc
|
||||
// filters[]=username:like:john
|
||||
// filters[]=role:eq:admin
|
||||
|
||||
// Example URL:
|
||||
GET /admins?page=1&size=10&sortBy=created_at&sortOrder=desc&filters[]=role:eq:admin
|
||||
|
||||
// Response:
|
||||
{
|
||||
"statusCode": 200,
|
||||
"message": "Success",
|
||||
"data": {
|
||||
"totalCount": 42,
|
||||
"items": [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"email": "admin@example.com",
|
||||
"role": "admin",
|
||||
"is_active": true,
|
||||
"created_at": "2024-01-01T00:00:00Z",
|
||||
"updated_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Get Single Admin
|
||||
```typescript
|
||||
// Backend endpoint: GET /admins/one/:id
|
||||
GET /admins/one/1
|
||||
|
||||
// Response:
|
||||
{
|
||||
"statusCode": 200,
|
||||
"message": "Success",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"username": "admin",
|
||||
"email": "admin@example.com",
|
||||
"role": "admin",
|
||||
"is_active": true,
|
||||
"created_at": "2024-01-01T00:00:00Z",
|
||||
"updated_at": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Update Admin
|
||||
```typescript
|
||||
// Backend endpoint: PATCH /admins/update/:id
|
||||
// Headers: Authorization: Bearer <token>
|
||||
// Request body:
|
||||
{
|
||||
"username": "updated_username",
|
||||
"email": "newemail@example.com",
|
||||
"is_active": false
|
||||
}
|
||||
```
|
||||
|
||||
### Delete Admin
|
||||
```typescript
|
||||
// Backend endpoint: DELETE /admins/:id
|
||||
// Headers: Authorization: Bearer <token>
|
||||
DELETE /admins/1
|
||||
```
|
||||
|
||||
## Filtering Examples
|
||||
|
||||
### Filter Rules
|
||||
- `eq`: Equals - `username:eq:john`
|
||||
- `neq`: Not equals - `role:neq:superadmin`
|
||||
- `gt`: Greater than - `id:gt:10`
|
||||
- `gte`: Greater than or equal - `id:gte:10`
|
||||
- `lt`: Less than - `id:lt:100`
|
||||
- `lte`: Less than or equal - `id:lte:100`
|
||||
- `like`: Case-insensitive contains - `username:like:john`
|
||||
- `nlike`: Not like - `username:nlike:test`
|
||||
- `in`: In array - `role:in:admin,superadmin`
|
||||
- `nin`: Not in array - `role:nin:admin`
|
||||
- `isnull`: Is null - `image:isnull:`
|
||||
- `isnotnull`: Is not null - `image:isnotnull:`
|
||||
- `between`: Between values - `id:between:10,20`
|
||||
|
||||
### Multiple Filters
|
||||
```
|
||||
GET /admins?filters[]=username:like:john&filters[]=role:eq:admin&filters[]=is_active:eq:true
|
||||
```
|
||||
|
||||
## Frontend Usage Examples
|
||||
|
||||
### Using React Query Hooks
|
||||
|
||||
```typescript
|
||||
// In a component
|
||||
import { useGetAdmins } from '@/hooks/api/admins';
|
||||
|
||||
function AdminsPage() {
|
||||
const { data, isLoading, error } = useGetAdmins({
|
||||
query: {
|
||||
page: 1,
|
||||
size: 25,
|
||||
sortBy: 'created_at',
|
||||
sortOrder: 'desc',
|
||||
},
|
||||
filters: [
|
||||
{ field: 'role', rule: 'eq', value: 'admin' },
|
||||
{ field: 'username', rule: 'like', value: 'john' },
|
||||
],
|
||||
});
|
||||
|
||||
if (isLoading) return <div>Loading...</div>;
|
||||
if (error) return <div>Error: {error.message}</div>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Total: {data?.data.totalCount}</p>
|
||||
{data?.data.items.map(admin => (
|
||||
<div key={admin.id}>{admin.username}</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Creating a Mutation Hook
|
||||
|
||||
```typescript
|
||||
// In hooks/api/admins.ts
|
||||
import { createPostMutationHook } from '@/api/helpers';
|
||||
import { CreateAdminSchema, AdminSchema } from '@/api/dtos/admin';
|
||||
|
||||
export const useCreateAdmin = createPostMutationHook({
|
||||
endpoint: '/auth/register',
|
||||
bodySchema: CreateAdminSchema,
|
||||
responseSchema: AdminSchema,
|
||||
rMutationParams: {
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['getAdmins'] });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Usage in component
|
||||
const createAdmin = useCreateAdmin();
|
||||
|
||||
const handleSubmit = async (formData) => {
|
||||
await createAdmin.mutateAsync({
|
||||
variables: formData,
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
## Telegram Bot Examples
|
||||
|
||||
### Adding a New Command
|
||||
|
||||
```typescript
|
||||
// In bot.service.ts
|
||||
public onModuleInit() {
|
||||
this.bot.command('start', this.onStart.bind(this));
|
||||
this.bot.command('help', this.onHelp.bind(this)); // New command
|
||||
this.bot.start();
|
||||
}
|
||||
|
||||
private async onHelp(ctx: Context) {
|
||||
await ctx.reply('Available commands:\n/start - Start the bot\n/help - Show help');
|
||||
}
|
||||
```
|
||||
|
||||
### Sending Messages from Backend
|
||||
|
||||
```typescript
|
||||
// In any service
|
||||
constructor(private readonly botService: BotService) {}
|
||||
|
||||
async notifyUser(telegramId: string, message: string) {
|
||||
await this.botService.sendMessage(telegramId, message);
|
||||
}
|
||||
|
||||
// With inline keyboard
|
||||
import { InlineKeyboard } from 'grammy';
|
||||
|
||||
const keyboard = new InlineKeyboard()
|
||||
.text('Button 1', 'callback_data_1')
|
||||
.row()
|
||||
.text('Button 2', 'callback_data_2');
|
||||
|
||||
await this.botService.sendMessage(telegramId, 'Choose an option:', keyboard);
|
||||
```
|
||||
|
||||
### Handling Callbacks
|
||||
|
||||
```typescript
|
||||
public onModuleInit() {
|
||||
this.bot.callbackQuery('callback_data_1', this.onCallback1.bind(this));
|
||||
}
|
||||
|
||||
private async onCallback1(ctx: Context) {
|
||||
await ctx.answerCallbackQuery();
|
||||
await ctx.reply('You clicked button 1!');
|
||||
}
|
||||
```
|
||||
|
||||
## Database Migration Examples
|
||||
|
||||
### Creating a Migration
|
||||
|
||||
```bash
|
||||
cd back
|
||||
pnpm migration:generate --name=add_user_table
|
||||
```
|
||||
|
||||
### Migration File Structure
|
||||
|
||||
```typescript
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddUserTable1234567890 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
CREATE TABLE "users" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"username" VARCHAR(255) NOT NULL,
|
||||
"created_at" TIMESTAMP NOT NULL DEFAULT now(),
|
||||
"updated_at" TIMESTAMP NOT NULL DEFAULT now(),
|
||||
CONSTRAINT "PK_users" PRIMARY KEY ("id")
|
||||
)
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`DROP TABLE "users"`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Setup
|
||||
|
||||
### .env.example Structure
|
||||
|
||||
```bash
|
||||
# Docker
|
||||
PROJECT_NAME=mybot
|
||||
|
||||
# Database
|
||||
DB_PORT=5432
|
||||
DB_NAME=mybot
|
||||
DB_USERNAME=mybot
|
||||
DB_PASSWORD=your_secure_password
|
||||
|
||||
# Backend
|
||||
BACK_PORT=4000
|
||||
JWT_SECRET=your_jwt_secret_here
|
||||
TELEGRAM_BOT_TOKEN=your_bot_token_here
|
||||
|
||||
# Frontend
|
||||
FRONT_PORT=3000
|
||||
API_URL=http://127.0.0.1:4000
|
||||
|
||||
# Backup (optional)
|
||||
BACKUP_DIR=/home/mybot/backups
|
||||
BACKUP_TELEGRAM_BOT_TOKEN=your_backup_bot_token
|
||||
BACKUP_TELEGRAM_CHAT_ID=your_chat_id
|
||||
```
|
||||
|
||||
### Generating JWT Secret
|
||||
|
||||
```javascript
|
||||
// In Node.js console
|
||||
require('crypto').randomBytes(32).toString('hex')
|
||||
```
|
||||
21
README.md
21
README.md
@ -94,3 +94,24 @@ pnpm migration:generate --name=my-migration-name
|
||||
- Dark/light theme
|
||||
- Docker-based development & production setup
|
||||
- Database backup with Telegram notification
|
||||
|
||||
## 🤖 Development with AI Assistants
|
||||
|
||||
This project is optimized for development with LLM assistants like Cursor AI, GitHub Copilot, etc.
|
||||
|
||||
### Key Files for AI Understanding:
|
||||
- **`.cursorrules`** - Project conventions, code style, and common patterns
|
||||
- **`AGENTS.md`** - Comprehensive architecture documentation and system design
|
||||
- **`EXAMPLES.md`** - API usage examples, code patterns, and implementation guides
|
||||
|
||||
### Quick Start for AI:
|
||||
1. Read `.cursorrules` for code style and conventions
|
||||
2. Check `AGENTS.md` for architecture overview and module structure
|
||||
3. See `EXAMPLES.md` for implementation patterns and API usage
|
||||
4. Follow the module structure: Entity → DTO → Service → Controller → Module
|
||||
|
||||
### Common Tasks:
|
||||
- **Adding a new feature**: See `AGENTS.md` → Development Workflow
|
||||
- **Creating API endpoints**: See `EXAMPLES.md` → Frontend Usage Examples
|
||||
- **Adding bot commands**: See `EXAMPLES.md` → Telegram Bot Examples
|
||||
- **Database migrations**: See `EXAMPLES.md` → Database Migration Examples
|
||||
|
||||
15
announcement.md
Normal file
15
announcement.md
Normal file
@ -0,0 +1,15 @@
|
||||
Опубликовали полнофункциональный шаблон (https://github.com/DionysusBenstein/nestjs-starter) для быстрого старта проектов на NestJS. Изначально делали для себя, чтобы не настраивать одно и то же в каждом новом проекте, но мы видим, что многие разработчики и команды сталкиваются с теми же проблемами.
|
||||
|
||||
Поэтому решили поделиться готовым решением, которое включает:
|
||||
• JWT аутентификация с access/refresh токенами
|
||||
• Управление пользователями (регистрация, верификация email, сброс пароля)
|
||||
• Email-сервис на BullMQ с шаблонами Handlebars
|
||||
• PostgreSQL + TypeORM с миграциями
|
||||
• Swagger документация с Dracula темой
|
||||
• Docker Compose для dev и prod сред
|
||||
|
||||
Всё это на современном стеке: NestJS 11, TypeScript 5, PostgreSQL 17, Redis, BullMQ.
|
||||
|
||||
Также у нас есть специализированный стартер для Telegram ботов с веб-админ-панелью — идеальное решение для проектов, где нужен бот с удобным интерфейсом управления. Включает готовую интеграцию с Grammy, систему управления администраторами с ролевой моделью (superadmin/admin), современный React-интерфейс на Mantine UI с поддержкой темной/светлой темы, таблицы данных с пагинацией, сортировкой и фильтрацией, а также автоматическое резервное копирование БД с уведомлениями в Telegram.
|
||||
|
||||
Шаблон открыт к вкладу сообщества - будем рады вашим PR и предложениям!
|
||||
@ -1,14 +1,14 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AdminConsoleModule } from './admin-console/admin-console.module';
|
||||
import { AdminsModule } from './admins/admins.module';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { BotModule } from './bot/bot.module';
|
||||
import { CommonModule } from './common/common.module';
|
||||
import { validate } from './config/env/validate';
|
||||
import { DatabaseModule } from './database/database.module';
|
||||
import { AdminsModule } from './admins/admins.module';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { AdminConsoleModule } from './admin-console/admin-console.module';
|
||||
import { BotModule } from './bot/bot.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
||||
@ -39,6 +39,24 @@ export class BotService {
|
||||
|
||||
/**
|
||||
* Send a message to a specific Telegram user.
|
||||
*
|
||||
* @param telegramId - Telegram user chat ID (as string)
|
||||
* @param message - Message text (supports Markdown)
|
||||
* @param reply_markup - Optional keyboard (inline, reply, or remove)
|
||||
* @throws Logs error if message sending fails
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Simple message
|
||||
* await botService.sendMessage('123456789', 'Hello!');
|
||||
*
|
||||
* // With inline keyboard
|
||||
* const keyboard = new InlineKeyboard()
|
||||
* .text('Button 1', 'data1')
|
||||
* .row()
|
||||
* .text('Button 2', 'data2');
|
||||
* await botService.sendMessage('123456789', 'Choose:', keyboard);
|
||||
* ```
|
||||
*/
|
||||
public async sendMessage(
|
||||
telegramId: string,
|
||||
|
||||
@ -29,7 +29,22 @@ interface IFilteringParams {
|
||||
value: string;
|
||||
}
|
||||
|
||||
// valid filter rules
|
||||
/**
|
||||
* Valid filter rules for query parameter filtering.
|
||||
*
|
||||
* Used with FilteringParams decorator to filter database queries.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // In controller
|
||||
* @Get()
|
||||
* findChunk(@FilteringParams(['username', 'role']) filtering: IFiltering) {
|
||||
* return this.service.findChunk(filtering);
|
||||
* }
|
||||
*
|
||||
* // Query: ?filters[]=username:like:john&filters[]=role:eq:admin
|
||||
* ```
|
||||
*/
|
||||
export enum FilterRule {
|
||||
EQUALS = 'eq',
|
||||
NOT_EQUALS = 'neq',
|
||||
@ -46,6 +61,15 @@ export enum FilterRule {
|
||||
BETWEEN = 'between',
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts filter parameters to TypeORM where clause.
|
||||
*
|
||||
* @param filter - Filter parameters with field, rule, and value
|
||||
* @returns TypeORM where clause object or empty object if invalid
|
||||
*
|
||||
* @internal
|
||||
* This function is used internally by FilteringParams decorator.
|
||||
*/
|
||||
export const getWhere = (filter: IFilteringParams) => {
|
||||
if (!filter) return {};
|
||||
|
||||
@ -86,6 +110,33 @@ function ensureObjectRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom decorator for parsing and validating filter query parameters.
|
||||
*
|
||||
* Supports nested filtering with dot notation (e.g., 'user.name:like:john').
|
||||
* Filters are passed as query parameter array: `filters[]=field:rule:value`
|
||||
*
|
||||
* @param allowedFields - Array of field names that can be filtered
|
||||
* @returns Decorator that extracts and validates filter parameters
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // In controller
|
||||
* @Get()
|
||||
* findChunk(
|
||||
* @FilteringParams(['username', 'role', 'is_active']) filtering: IFiltering
|
||||
* ) {
|
||||
* return this.service.findChunk(filtering);
|
||||
* }
|
||||
*
|
||||
* // Query examples:
|
||||
* // ?filters[]=username:like:john
|
||||
* // ?filters[]=role:eq:admin&filters[]=is_active:eq:true
|
||||
* // ?filters[]=id:between:10,20
|
||||
* ```
|
||||
*
|
||||
* @throws BadRequestException if filter format is invalid or field is not allowed
|
||||
*/
|
||||
export const FilteringParams = createParamDecorator(
|
||||
(data: readonly string[], ctx: ExecutionContext): IFiltering | null => {
|
||||
const req: Request = ctx.switchToHttp().getRequest();
|
||||
|
||||
@ -2,18 +2,60 @@ import { BadRequestException, createParamDecorator, ExecutionContext } from '@ne
|
||||
import { Request } from 'express';
|
||||
import { ErrorCode } from '../enums/error-code.enum';
|
||||
|
||||
/**
|
||||
* Pagination parameters extracted from query string.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Query: ?page=2&size=25
|
||||
* // Results in: { limit: 25, offset: 25, page: 2 }
|
||||
* ```
|
||||
*/
|
||||
export interface IPagination {
|
||||
/** Maximum number of items to return */
|
||||
limit: number;
|
||||
/** Number of items to skip */
|
||||
offset: number;
|
||||
page?: number; // for infinite scroll on client side
|
||||
/** Current page number (1-indexed, for infinite scroll on client side) */
|
||||
page?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paginated resource response structure.
|
||||
*
|
||||
* @template T - Type of items in the paginated list
|
||||
*/
|
||||
export type PaginatedResource<T> = {
|
||||
/** Total number of items matching the query */
|
||||
totalCount: number;
|
||||
/** Array of items for the current page */
|
||||
items: T[];
|
||||
page?: number; // for infinite scroll on client side
|
||||
/** Current page number (for infinite scroll on client side) */
|
||||
page?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom decorator for parsing pagination query parameters.
|
||||
*
|
||||
* Extracts `page` and `size` from query string and converts to limit/offset.
|
||||
* Page is 1-indexed. Maximum size is 250.
|
||||
*
|
||||
* @returns Decorator that extracts pagination parameters
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // In controller
|
||||
* @Get()
|
||||
* findChunk(@PaginationParams() pagination: IPagination) {
|
||||
* return this.service.findChunk(pagination);
|
||||
* }
|
||||
*
|
||||
* // Query: ?page=2&size=25
|
||||
* // Results in: { limit: 25, offset: 25, page: 2 }
|
||||
* ```
|
||||
*
|
||||
* @throws BadRequestException if page or size are invalid or size > 250
|
||||
*/
|
||||
export const PaginationParams = createParamDecorator((data, ctx: ExecutionContext): IPagination => {
|
||||
const req: Request = ctx.switchToHttp().getRequest();
|
||||
const page = parseInt(req.query.page as string);
|
||||
|
||||
@ -2,12 +2,48 @@ import { BadRequestException, createParamDecorator, ExecutionContext } from '@ne
|
||||
import { Request } from 'express';
|
||||
import { ErrorCode } from '../enums/error-code.enum';
|
||||
|
||||
/**
|
||||
* Sort direction for database queries.
|
||||
*/
|
||||
type Direction = 'ASC' | 'DESC';
|
||||
|
||||
/**
|
||||
* Sorting parameters extracted from query string.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Query: ?sort=created_at:DESC
|
||||
* // Results in: { created_at: 'DESC' }
|
||||
* ```
|
||||
*/
|
||||
export interface ISorting {
|
||||
/** Field name mapped to sort direction */
|
||||
[field: string]: Direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom decorator for parsing sorting query parameters.
|
||||
*
|
||||
* Extracts `sort` from query string in format `field:direction`.
|
||||
* Validates that the field is in the allowed list.
|
||||
*
|
||||
* @param validParams - Array of field names that can be sorted
|
||||
* @returns Decorator that extracts and validates sort parameters
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // In controller
|
||||
* @Get()
|
||||
* findChunk(@SortingParams(['id', 'created_at', 'username']) sorting: ISorting) {
|
||||
* return this.service.findChunk(sorting);
|
||||
* }
|
||||
*
|
||||
* // Query: ?sort=created_at:DESC
|
||||
* // Results in: { created_at: 'DESC' }
|
||||
* ```
|
||||
*
|
||||
* @throws BadRequestException if sort format is invalid or field is not allowed
|
||||
*/
|
||||
export const SortingParams = createParamDecorator((validParams, ctx: ExecutionContext): ISorting => {
|
||||
const req: Request = ctx.switchToHttp().getRequest();
|
||||
const sort = req.query.sort as string;
|
||||
|
||||
@ -4,6 +4,23 @@ import {
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
/**
|
||||
* Abstract base entity that provides common fields for all database entities.
|
||||
*
|
||||
* All entities should extend this class to get:
|
||||
* - `id`: Auto-incrementing primary key
|
||||
* - `created_at`: Timestamp when record was created
|
||||
* - `updated_at`: Timestamp when record was last updated
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @Entity('users')
|
||||
* export class User extends AbstractEntity {
|
||||
* @Column()
|
||||
* name: string;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export abstract class AbstractEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
public id: number;
|
||||
|
||||
61
back/src/common/types/api.types.ts
Normal file
61
back/src/common/types/api.types.ts
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Standard API response wrapper used throughout the application.
|
||||
*
|
||||
* All API endpoints return responses in this format for consistency.
|
||||
*
|
||||
* @template T - Type of the data payload
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Success response
|
||||
* {
|
||||
* statusCode: 200,
|
||||
* message: "Success",
|
||||
* data: { id: 1, name: "John" }
|
||||
* }
|
||||
*
|
||||
* // Error response
|
||||
* {
|
||||
* statusCode: 400,
|
||||
* message: "Validation failed",
|
||||
* data: null
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export interface ApiResponse<T> {
|
||||
/** HTTP status code */
|
||||
statusCode: number;
|
||||
/** Human-readable message */
|
||||
message: string;
|
||||
/** Response payload data */
|
||||
data: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paginated response structure for list endpoints.
|
||||
*
|
||||
* Used with pagination decorator to return paginated results.
|
||||
*
|
||||
* @template T - Type of items in the paginated list
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* {
|
||||
* statusCode: 200,
|
||||
* message: "Success",
|
||||
* data: {
|
||||
* totalCount: 100,
|
||||
* items: [
|
||||
* { id: 1, name: "Item 1" },
|
||||
* { id: 2, name: "Item 2" }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export interface PaginatedResponse<T> {
|
||||
/** Total number of items matching the query */
|
||||
totalCount: number;
|
||||
/** Array of items for the current page */
|
||||
items: T[];
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user