Optimize code for AI assistents

This commit is contained in:
Денис 2026-02-17 16:07:42 +03:00
parent aa19c08292
commit 8140c86dfe
14 changed files with 1300 additions and 8 deletions

99
.cursorrules Normal file
View 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
View 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
View 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
View 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
View 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')
```

View File

@ -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
View 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 и предложениям!

View File

@ -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: [

View File

@ -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,

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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;

View 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[];
}