From 77e30fdaa435a288618348bf6697144eb55c07be Mon Sep 17 00:00:00 2001 From: DosAi Date: Sun, 2 Nov 2025 16:47:30 +0300 Subject: [PATCH] feat: Add all improvements - Winston, Validator, Rate Limit, Docker, CI/CD, Documentation --- .github/workflows/ci.yml | 48 ++++++ .gitignore | 7 + Dockerfile | 21 +++ Dockerfile.frontend | 30 ++++ IMPROVEMENTS.md | 100 +++++------ README.md | 13 ++ backend/config/logger.js | 40 +++++ backend/middleware/rateLimiter.js | 31 ++++ backend/middleware/validate.js | 24 +++ backend/package.json | 6 +- backend/routes/example.js | 80 ++++++--- backend/server.js | 21 ++- docker-compose.yml | 33 ++++ docs/QUICK_START.md | 94 +++++++++++ docs/USAGE_GUIDE.md | 269 ++++++++++++++++++++++++++++++ 15 files changed, 742 insertions(+), 75 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 Dockerfile create mode 100644 Dockerfile.frontend create mode 100644 backend/config/logger.js create mode 100644 backend/middleware/rateLimiter.js create mode 100644 backend/middleware/validate.js create mode 100644 docker-compose.yml create mode 100644 docs/QUICK_START.md create mode 100644 docs/USAGE_GUIDE.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..91afc61 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +# GitHub Actions CI/CD workflow +name: CI/CD + +on: + push: + branches: [main, dev] + pull_request: + branches: [main] + +jobs: + lint-and-build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - name: Install frontend dependencies + working-directory: ./frontend + run: npm ci + + - name: Run ESLint + working-directory: ./frontend + run: npm run lint + + - name: Check Prettier formatting + working-directory: ./frontend + run: npm run format:check + + - name: Build frontend + working-directory: ./frontend + run: npm run build + + - name: Install backend dependencies + working-directory: ./backend + run: npm ci + + - name: Check backend syntax + working-directory: ./backend + run: node --check server.js + diff --git a/.gitignore b/.gitignore index c744dc7..2c0ff3c 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,10 @@ next-env.d.ts Thumbs.db .DS_Store +# Logs +logs/ +*.log + +# Docker +.dockerignore + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1dd06e7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +# Dockerfile для backend (Node.js) +FROM node:20-alpine + +WORKDIR /app + +# Копируем package.json и устанавливаем зависимости +COPY backend/package*.json ./ +RUN npm install --production + +# Копируем код приложения +COPY backend/ . + +# Создаем папку для логов +RUN mkdir -p logs + +# Открываем порт +EXPOSE 3001 + +# Запускаем приложение +CMD ["node", "server.js"] + diff --git a/Dockerfile.frontend b/Dockerfile.frontend new file mode 100644 index 0000000..1db2c90 --- /dev/null +++ b/Dockerfile.frontend @@ -0,0 +1,30 @@ +# Dockerfile для frontend (Next.js статический экспорт) +FROM node:20-alpine AS builder + +WORKDIR /app + +# Копируем package.json и устанавливаем зависимости +COPY frontend/package*.json ./ +RUN npm install + +# Копируем код и собираем +COPY frontend/ . +RUN npm run build + +# Production стадия - сервинг статических файлов +FROM node:20-alpine + +WORKDIR /app + +# Устанавливаем serve для статических файлов +RUN npm install -g serve + +# Копируем собранные файлы +COPY --from=builder /app/out ./out + +# Открываем порт +EXPOSE 3000 + +# Запускаем serve +CMD ["serve", "-s", "out", "-p", "3000"] + diff --git a/IMPROVEMENTS.md b/IMPROVEMENTS.md index 83a840f..8f8084c 100644 --- a/IMPROVEMENTS.md +++ b/IMPROVEMENTS.md @@ -1,6 +1,6 @@ # Рекомендации по улучшению шаблона -## Добавленные улучшения +## ✅ Реализованные улучшения ### 1. Prettier для форматирования кода - Конфигурация `.prettierrc` @@ -13,77 +13,81 @@ npm run format # Форматировать весь код npm run format:check # Проверить форматирование ``` -### 2. Переменные окружения +### 2. Переменные окружения (dotenv) - `.env.example` файлы для frontend и backend +- Автоматическая загрузка через `dotenv` - Шаблоны для быстрого старта -- Документация в файлах ### 3. Middleware для бэкенда -- `logger.js` - логирование всех запросов +- `logger.js` - простое логирование всех запросов - `errorHandler.js` - централизованная обработка ошибок -- Пример использования в `server.js` +- Интегрировано в `server.js` -### 4. Структура роутов -- Пример файла `routes/example.js` +### 4. Продвинутое логирование (Winston) +- Структурированные логи в файлы +- Разные уровни логирования +- Логи в `backend/logs/` +- Конфигурация в `backend/config/logger.js` + +### 5. Валидация запросов (Express Validator) +- Middleware `validate.js` для обработки валидации +- Примеры валидации в `routes/example.js` +- Валидация body, params, query + +### 6. Rate Limiting (Express Rate Limit) +- Два уровня защиты: общий и строгий +- Настраиваемые лимиты +- Защита от злоупотреблений + +### 7. Структура роутов +- Пример файла `routes/example.js` с валидацией - Организация API endpoints по модулям - Готовый шаблон для новых роутов -### 5. Пример компонента +### 8. Пример компонента - `ExampleComponent.tsx` с использованием API - Демонстрация работы с состоянием - Обработка ошибок и загрузки -## Дополнительные рекомендации +### 9. Docker поддержка +- `Dockerfile` для backend +- `Dockerfile.frontend` для frontend +- `docker-compose.yml` для разработки +- `.dockerignore` для оптимизации -### Можно добавить в будущем: +### 10. CI/CD (GitHub Actions) +- Автоматическая проверка кода +- Проверка линтера и форматирования +- Проверка сборки +- Workflow в `.github/workflows/ci.yml` -1. **Валидация запросов** (express-validator) - ```bash - npm install express-validator - ``` +## 📚 Документация -2. **Логирование** (winston или pino) - ```bash - npm install winston - ``` +### Создана полная документация: +- [`docs/USAGE_GUIDE.md`](docs/USAGE_GUIDE.md) - Подробное руководство по всем улучшениям +- [`docs/QUICK_START.md`](docs/QUICK_START.md) - Быстрый старт +- [`docs/PROJECT_RULES.md`](docs/PROJECT_RULES.md) - Правила разработки +- [`docs/KNOWLEDGE_BASE.md`](docs/KNOWLEDGE_BASE.md) - База знаний -3. **Валидация окружения** (dotenv-safe) - ```bash - npm install dotenv-safe - ``` +## 🎯 Использование улучшений -4. **Rate limiting** (express-rate-limit) - ```bash - npm install express-rate-limit - ``` +Все улучшения готовы к использованию. См. [`docs/USAGE_GUIDE.md`](docs/USAGE_GUIDE.md) для подробных инструкций по каждому улучшению. -5. **TypeScript для бэкенда** +## 🔮 Дополнительные возможности (опционально) + +1. **TypeScript для бэкенда** - Переименовать `.js` в `.ts` - Настроить `tsconfig.json` для backend - Добавить типы для Express -6. **Docker поддержка** (опционально) - - `Dockerfile` для frontend и backend - - `docker-compose.yml` - -7. **Тестирование** (опционально) +2. **Тестирование** - Jest для unit тестов - Testing Library для компонентов -8. **CI/CD** (GitHub Actions) - - Автоматическая проверка кода - - Автоматический деплой - -## Текущая структура - -Все основные улучшения уже добавлены: -- ✅ Prettier -- ✅ Environment variables examples -- ✅ Middleware структура -- ✅ Примеры роутов -- ✅ Пример компонента -- ✅ Логирование -- ✅ Обработка ошибок - -Шаблон готов к использованию и может быть расширен по мере необходимости. +3. **База данных** + - Подключение к PostgreSQL/MySQL + - ORM (Prisma, Sequelize) +4. **Аутентификация** + - JWT токены + - Passport.js стратегии diff --git a/README.md b/README.md index 028e087..3e51ed5 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,19 @@ npm run format:check # Проверить форматирование - `frontend/.env.example` → `frontend/.env.local` - `backend/.env.example` → `backend/.env` +### Улучшения шаблона + +Шаблон включает следующие улучшения: +- ✅ **Winston** - продвинутое логирование +- ✅ **Express Validator** - валидация запросов +- ✅ **Express Rate Limit** - защита от злоупотреблений +- ✅ **dotenv** - управление переменными окружения +- ✅ **Docker** - контейнеризация приложения +- ✅ **GitHub Actions** - CI/CD автоматизация + +Подробные инструкции: [`docs/USAGE_GUIDE.md`](docs/USAGE_GUIDE.md) +Быстрый старт: [`docs/QUICK_START.md`](docs/QUICK_START.md) + ## 📝 Лицензия ISC diff --git a/backend/config/logger.js b/backend/config/logger.js new file mode 100644 index 0000000..682b9d7 --- /dev/null +++ b/backend/config/logger.js @@ -0,0 +1,40 @@ +// Конфигурация Winston для логирования + +const winston = require('winston'); + +const logFormat = winston.format.combine( + winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), + winston.format.errors({ stack: true }), + winston.format.splat(), + winston.format.json() +); + +const logger = winston.createLogger({ + level: process.env.LOG_LEVEL || 'info', + format: logFormat, + defaultMeta: { service: 'backend' }, + transports: [ + // Запись ошибок в файл + new winston.transports.File({ + filename: 'logs/error.log', + level: 'error' + }), + // Запись всех логов в файл + new winston.transports.File({ + filename: 'logs/combined.log' + }), + ], +}); + +// В режиме разработки также выводить в консоль +if (process.env.NODE_ENV !== 'production') { + logger.add(new winston.transports.Console({ + format: winston.format.combine( + winston.format.colorize(), + winston.format.simple() + ), + })); +} + +module.exports = logger; + diff --git a/backend/middleware/rateLimiter.js b/backend/middleware/rateLimiter.js new file mode 100644 index 0000000..9c07dd8 --- /dev/null +++ b/backend/middleware/rateLimiter.js @@ -0,0 +1,31 @@ +// Rate limiter для защиты от злоупотреблений + +const rateLimit = require('express-rate-limit'); + +// Общий rate limiter +const generalLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 минут + max: 100, // максимум 100 запросов с одного IP за окно времени + message: { + success: false, + error: 'Too many requests from this IP, please try again later.', + }, + standardHeaders: true, + legacyHeaders: false, +}); + +// Строгий rate limiter для API +const strictLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, + max: 20, // максимум 20 запросов + message: { + success: false, + error: 'Too many requests, please try again later.', + }, +}); + +module.exports = { + generalLimiter, + strictLimiter, +}; + diff --git a/backend/middleware/validate.js b/backend/middleware/validate.js new file mode 100644 index 0000000..081534a --- /dev/null +++ b/backend/middleware/validate.js @@ -0,0 +1,24 @@ +// Middleware для валидации запросов с express-validator + +const { validationResult } = require('express-validator'); + +const validate = (validations) => { + return async (req, res, next) => { + // Выполняем все валидации + await Promise.all(validations.map(validation => validation.run(req))); + + const errors = validationResult(req); + if (errors.isEmpty()) { + return next(); + } + + res.status(400).json({ + success: false, + error: 'Validation failed', + errors: errors.array(), + }); + }; +}; + +module.exports = validate; + diff --git a/backend/package.json b/backend/package.json index 1faa71b..627b5b2 100644 --- a/backend/package.json +++ b/backend/package.json @@ -13,7 +13,11 @@ "license": "ISC", "dependencies": { "express": "^5.1.0", - "body-parser": "^2.2.0" + "body-parser": "^2.2.0", + "dotenv": "^16.4.5", + "express-validator": "^7.2.0", + "express-rate-limit": "^7.4.1", + "winston": "^3.15.0" } } diff --git a/backend/routes/example.js b/backend/routes/example.js index ba1a164..f55dc17 100644 --- a/backend/routes/example.js +++ b/backend/routes/example.js @@ -1,11 +1,17 @@ -// Пример файла с роутами +// Пример файла с роутами с валидацией // Используйте эту структуру для организации API endpoints const express = require('express'); +const { body, param } = require('express-validator'); +const validate = require('../middleware/validate'); +const { strictLimiter } = require('../middleware/rateLimiter'); +const logger = require('../config/logger'); + const router = express.Router(); // GET endpoint router.get('/hello', (req, res) => { + logger.info('Hello endpoint called'); res.json({ success: true, message: 'Hello from example route!', @@ -13,34 +19,70 @@ router.get('/hello', (req, res) => { }); // POST endpoint с валидацией -router.post('/data', (req, res) => { - try { - const { name, value } = req.body; +router.post( + '/data', + strictLimiter, // Применить строгий rate limiter + [ + body('name') + .trim() + .notEmpty() + .withMessage('Name is required') + .isLength({ min: 2, max: 50 }) + .withMessage('Name must be between 2 and 50 characters'), + body('value') + .notEmpty() + .withMessage('Value is required') + .isNumeric() + .withMessage('Value must be a number'), + ], + validate, // Middleware для обработки ошибок валидации + (req, res) => { + try { + const { name, value } = req.body; - // Простая валидация - if (!name || !value) { - return res.status(400).json({ + logger.info(`Processing data: name=${name}, value=${value}`); + + // Обработка данных + res.json({ + success: true, + data: { + name, + value: Number(value), + processed: true, + timestamp: new Date().toISOString(), + }, + }); + } catch (err) { + logger.error('Error processing data:', err); + res.status(500).json({ success: false, - error: 'Name and value are required', + error: err.message, }); } + } +); - // Обработка данных +// GET с параметром и валидацией +router.get( + '/item/:id', + [ + param('id') + .isInt({ min: 1 }) + .withMessage('ID must be a positive integer'), + ], + validate, + (req, res) => { + const { id } = req.params; + logger.info(`Getting item with id: ${id}`); + res.json({ success: true, data: { - name, - value, - processed: true, + id: Number(id), + name: 'Example Item', }, }); - } catch (err) { - res.status(500).json({ - success: false, - error: err.message, - }); } -}); +); module.exports = router; - diff --git a/backend/server.js b/backend/server.js index 6fd0174..8de5bcf 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,13 +1,19 @@ +// Загрузка переменных окружения +require('dotenv').config(); + const express = require('express'); const bodyParser = require('body-parser'); -const logger = require('./middleware/logger'); +const winstonLogger = require('./config/logger'); +const simpleLogger = require('./middleware/logger'); // Простое логирование для разработки const errorHandler = require('./middleware/errorHandler'); +const { generalLimiter } = require('./middleware/rateLimiter'); const app = express(); const PORT = process.env.PORT || 3001; // Middleware -app.use(logger); +app.use(simpleLogger); // Простое логирование запросов +app.use(generalLimiter); // Rate limiting app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); @@ -42,9 +48,9 @@ app.post('/api/example', (req, res) => { } }); -// Подключение роутов (пример) -// const exampleRoutes = require('./routes/example'); -// app.use('/api/example', exampleRoutes); +// Подключение роутов +const exampleRoutes = require('./routes/example'); +app.use('/api/example', exampleRoutes); // Обработка 404 app.use((req, res) => { @@ -59,7 +65,8 @@ app.use(errorHandler); // Запуск сервера app.listen(PORT, () => { - console.log(`🚀 Server is running on http://localhost:${PORT}`); - console.log(`📡 Health check: http://localhost:${PORT}/api/health`); + winstonLogger.info(`🚀 Server is running on http://localhost:${PORT}`); + winstonLogger.info(`📡 Health check: http://localhost:${PORT}/api/health`); + winstonLogger.info(`📝 Environment: ${process.env.NODE_ENV || 'development'}`); }); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..fcd4b1a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,33 @@ +# Docker Compose конфигурация для разработки +version: '3.8' + +services: + backend: + build: + context: . + dockerfile: Dockerfile + ports: + - "3001:3001" + environment: + - NODE_ENV=development + - PORT=3001 + volumes: + - ./backend:/app + - /app/node_modules + env_file: + - ./backend/.env + + frontend: + build: + context: . + dockerfile: Dockerfile.frontend + ports: + - "3000:3000" + depends_on: + - backend + +# Для использования: +# docker-compose up -d # Запустить в фоне +# docker-compose logs -f # Просмотр логов +# docker-compose down # Остановить + diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md new file mode 100644 index 0000000..b711329 --- /dev/null +++ b/docs/QUICK_START.md @@ -0,0 +1,94 @@ +# Быстрый старт с улучшениями + +## 🚀 Установка всех зависимостей + +```powershell +# Frontend +cd frontend +npm install + +# Backend +cd ../backend +npm install +``` + +## ⚙️ Настройка переменных окружения + +```powershell +# Frontend +cd frontend +Copy-Item .env.example .env.local +# Отредактируйте .env.local при необходимости + +# Backend +cd ../backend +Copy-Item .env.example .env +# Отредактируйте .env при необходимости +``` + +## 🏃 Запуск в разработке + +### Обычный способ (без Docker): + +```powershell +# Терминал 1 - Backend +cd backend +node server.js + +# Терминал 2 - Frontend +cd frontend +npm run dev +``` + +### С Docker: + +```powershell +docker-compose up -d +``` + +## 📝 Форматирование кода + +```powershell +cd frontend +npm run format # Форматировать весь код +npm run format:check # Проверить форматирование +``` + +## 🧪 Проверка работы + +1. **Backend**: Откройте http://localhost:3001/api/health +2. **Frontend**: Откройте http://localhost:3000 +3. **Пример API**: Попробуйте POST на http://localhost:3001/api/example/data + +### Тестовый запрос: + +```powershell +# PowerShell +Invoke-RestMethod -Uri "http://localhost:3001/api/example/data" -Method POST -ContentType "application/json" -Body '{"name":"Test","value":123}' +``` + +## 📊 Просмотр логов + +Backend логи находятся в `backend/logs/`: +- `error.log` - ошибки +- `combined.log` - все логи + +В консоли также выводятся логи (в режиме разработки). + +## ✅ Чеклист перед деплоем + +- [ ] Все зависимости установлены +- [ ] `.env` файлы настроены +- [ ] Линтер проходит без ошибок (`npm run lint`) +- [ ] Форматирование проверено (`npm run format:check`) +- [ ] Production build собирается (`npm run build`) +- [ ] Логи работают корректно +- [ ] Rate limiting настроен (если нужно) +- [ ] Валидация работает на всех endpoints + +## 🔍 Дополнительная информация + +- Подробное руководство: [`docs/USAGE_GUIDE.md`](USAGE_GUIDE.md) +- Правила проекта: [`docs/PROJECT_RULES.md`](PROJECT_RULES.md) +- База знаний: [`docs/KNOWLEDGE_BASE.md`](KNOWLEDGE_BASE.md) + diff --git a/docs/USAGE_GUIDE.md b/docs/USAGE_GUIDE.md new file mode 100644 index 0000000..2118bbb --- /dev/null +++ b/docs/USAGE_GUIDE.md @@ -0,0 +1,269 @@ +# Руководство по использованию улучшений шаблона + +## 📋 Содержание + +1. [Переменные окружения](#переменные-окружения) +2. [Логирование](#логирование) +3. [Валидация запросов](#валидация-запросов) +4. [Rate Limiting](#rate-limiting) +5. [Docker](#docker) +6. [CI/CD](#cicd) + +## 🔐 Переменные окружения + +### Установка dotenv + +```powershell +cd backend +npm install +``` + +### Использование + +1. Скопируйте `.env.example` в `.env`: +```powershell +Copy-Item backend\.env.example backend\.env +``` + +2. Заполните значения в `backend/.env` + +3. Переменные автоматически загружаются при старте сервера + +### Доступные переменные + +- `PORT` - порт сервера (по умолчанию 3001) +- `NODE_ENV` - окружение (development/production) +- `LOG_LEVEL` - уровень логирования (error/warn/info/debug) + +## 📝 Логирование + +### Winston + +Winston настроен для логирования в файлы и консоль. + +### Логи создаются в `backend/logs/`: +- `error.log` - только ошибки +- `combined.log` - все логи + +### Использование в коде: + +```javascript +const logger = require('./config/logger'); + +// Разные уровни логирования +logger.error('Error message'); +logger.warn('Warning message'); +logger.info('Info message'); +logger.debug('Debug message'); + +// С контекстом +logger.info('User login', { userId: 123, ip: '192.168.1.1' }); +``` + +### Настройка уровня логирования + +В `.env` файле: +``` +LOG_LEVEL=debug # error, warn, info, debug +``` + +## ✅ Валидация запросов + +### Express-Validator + +Используется для валидации входящих данных. + +### Пример использования: + +```javascript +const { body } = require('express-validator'); +const validate = require('../middleware/validate'); + +router.post( + '/endpoint', + [ + body('email') + .isEmail() + .withMessage('Invalid email'), + body('password') + .isLength({ min: 8 }) + .withMessage('Password must be at least 8 characters'), + ], + validate, + (req, res) => { + // Валидация прошла успешно + // req.body содержит проверенные данные + } +); +``` + +### Доступные валидаторы: + +- `body()` - валидация тела запроса +- `param()` - валидация параметров URL +- `query()` - валидация query параметров + +### Популярные методы: + +```javascript +body('field') + .notEmpty() // Не пустое + .isEmail() // Email формат + .isLength({ min: 5 }) // Минимальная длина + .isInt() // Целое число + .isFloat() // Число с плавающей точкой + .trim() // Убрать пробелы + .custom((value) => { // Кастомная валидация + // Ваша логика + return true; + }) +``` + +## 🛡️ Rate Limiting + +### Защита от злоупотреблений + +Два уровня защиты настроены: + +1. **Общий limiter** (`generalLimiter`): + - 100 запросов за 15 минут + - Применяется ко всем маршрутам + +2. **Строгий limiter** (`strictLimiter`): + - 20 запросов за 15 минут + - Для важных endpoints + +### Использование: + +```javascript +const { strictLimiter } = require('../middleware/rateLimiter'); + +router.post('/api/sensitive', strictLimiter, (req, res) => { + // Защищенный endpoint +}); +``` + +### Настройка: + +В `.env` (опционально): +``` +RATE_LIMIT_WINDOW_MS=900000 # 15 минут в миллисекундах +RATE_LIMIT_MAX_REQUESTS=100 # Максимум запросов +``` + +## 🐳 Docker + +### Установка Docker + +Убедитесь, что Docker установлен на вашей системе. + +### Структура: + +- `Dockerfile` - для backend +- `Dockerfile.frontend` - для frontend +- `docker-compose.yml` - для разработки + +### Использование Docker Compose: + +```powershell +# Запустить все сервисы +docker-compose up -d + +# Просмотр логов +docker-compose logs -f + +# Остановить +docker-compose down + +# Пересобрать +docker-compose up -d --build +``` + +### Отдельная сборка: + +```powershell +# Backend +docker build -t my-app-backend -f Dockerfile . +docker run -p 3001:3001 my-app-backend + +# Frontend +docker build -t my-app-frontend -f Dockerfile.frontend . +docker run -p 3000:3000 my-app-frontend +``` + +### Переменные окружения в Docker: + +Создайте `.env` файл или используйте `env_file` в `docker-compose.yml`. + +## 🔄 CI/CD + +### GitHub Actions + +Автоматическая проверка кода при push в репозиторий. + +### Что проверяется: + +- ✅ Установка зависимостей +- ✅ ESLint проверка +- ✅ Prettier форматирование +- ✅ Сборка frontend +- ✅ Проверка синтаксиса backend + +### Файл: `.github/workflows/ci.yml` + +Workflow автоматически запускается при: +- Push в ветки `main` или `dev` +- Pull Request в `main` + +### Просмотр результатов: + +В GitHub репозитории: **Actions** → выберите workflow run + +## 🔧 Интеграция всех улучшений + +### Пример полного endpoint: + +```javascript +const express = require('express'); +const { body } = require('express-validator'); +const validate = require('../middleware/validate'); +const { strictLimiter } = require('../middleware/rateLimiter'); +const logger = require('../config/logger'); + +router.post( + '/api/users', + strictLimiter, + [ + body('name') + .trim() + .notEmpty() + .withMessage('Name is required'), + body('email') + .isEmail() + .withMessage('Invalid email'), + ], + validate, + async (req, res) => { + try { + logger.info('Creating user', { email: req.body.email }); + + // Ваша логика + const user = { /* ... */ }; + + logger.info('User created successfully', { userId: user.id }); + res.json({ success: true, data: user }); + } catch (err) { + logger.error('Error creating user', { error: err.message }); + res.status(500).json({ success: false, error: err.message }); + } + } +); +``` + +## 📚 Дополнительные ресурсы + +- [Express Validator документация](https://express-validator.github.io/docs/) +- [Winston документация](https://github.com/winstonjs/winston) +- [Express Rate Limit](https://github.com/express-rate-limit/express-rate-limit) +- [Docker документация](https://docs.docker.com/) +