feat: Add improvements - Prettier, env examples, middleware, examples
This commit is contained in:
parent
981d5eb71e
commit
da1de34d21
8
.prettierignore
Normal file
8
.prettierignore
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
node_modules
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
*.log
|
||||||
|
.env*
|
||||||
|
|
||||||
11
.prettierrc
Normal file
11
.prettierrc
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"singleQuote": false,
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"arrowParens": "always",
|
||||||
|
"endOfLine": "lf"
|
||||||
|
}
|
||||||
|
|
||||||
89
IMPROVEMENTS.md
Normal file
89
IMPROVEMENTS.md
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# Рекомендации по улучшению шаблона
|
||||||
|
|
||||||
|
## Добавленные улучшения
|
||||||
|
|
||||||
|
### 1. Prettier для форматирования кода
|
||||||
|
- Конфигурация `.prettierrc`
|
||||||
|
- Игнорирование файлов `.prettierignore`
|
||||||
|
- Скрипты в package.json для форматирования
|
||||||
|
|
||||||
|
**Использование:**
|
||||||
|
```powershell
|
||||||
|
npm run format # Форматировать весь код
|
||||||
|
npm run format:check # Проверить форматирование
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Переменные окружения
|
||||||
|
- `.env.example` файлы для frontend и backend
|
||||||
|
- Шаблоны для быстрого старта
|
||||||
|
- Документация в файлах
|
||||||
|
|
||||||
|
### 3. Middleware для бэкенда
|
||||||
|
- `logger.js` - логирование всех запросов
|
||||||
|
- `errorHandler.js` - централизованная обработка ошибок
|
||||||
|
- Пример использования в `server.js`
|
||||||
|
|
||||||
|
### 4. Структура роутов
|
||||||
|
- Пример файла `routes/example.js`
|
||||||
|
- Организация API endpoints по модулям
|
||||||
|
- Готовый шаблон для новых роутов
|
||||||
|
|
||||||
|
### 5. Пример компонента
|
||||||
|
- `ExampleComponent.tsx` с использованием API
|
||||||
|
- Демонстрация работы с состоянием
|
||||||
|
- Обработка ошибок и загрузки
|
||||||
|
|
||||||
|
## Дополнительные рекомендации
|
||||||
|
|
||||||
|
### Можно добавить в будущем:
|
||||||
|
|
||||||
|
1. **Валидация запросов** (express-validator)
|
||||||
|
```bash
|
||||||
|
npm install express-validator
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Логирование** (winston или pino)
|
||||||
|
```bash
|
||||||
|
npm install winston
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Валидация окружения** (dotenv-safe)
|
||||||
|
```bash
|
||||||
|
npm install dotenv-safe
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Rate limiting** (express-rate-limit)
|
||||||
|
```bash
|
||||||
|
npm install express-rate-limit
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **TypeScript для бэкенда**
|
||||||
|
- Переименовать `.js` в `.ts`
|
||||||
|
- Настроить `tsconfig.json` для backend
|
||||||
|
- Добавить типы для Express
|
||||||
|
|
||||||
|
6. **Docker поддержка** (опционально)
|
||||||
|
- `Dockerfile` для frontend и backend
|
||||||
|
- `docker-compose.yml`
|
||||||
|
|
||||||
|
7. **Тестирование** (опционально)
|
||||||
|
- Jest для unit тестов
|
||||||
|
- Testing Library для компонентов
|
||||||
|
|
||||||
|
8. **CI/CD** (GitHub Actions)
|
||||||
|
- Автоматическая проверка кода
|
||||||
|
- Автоматический деплой
|
||||||
|
|
||||||
|
## Текущая структура
|
||||||
|
|
||||||
|
Все основные улучшения уже добавлены:
|
||||||
|
- ✅ Prettier
|
||||||
|
- ✅ Environment variables examples
|
||||||
|
- ✅ Middleware структура
|
||||||
|
- ✅ Примеры роутов
|
||||||
|
- ✅ Пример компонента
|
||||||
|
- ✅ Логирование
|
||||||
|
- ✅ Обработка ошибок
|
||||||
|
|
||||||
|
Шаблон готов к использованию и может быть расширен по мере необходимости.
|
||||||
|
|
||||||
20
README.md
20
README.md
@ -136,6 +136,22 @@ pm2 start frontend/.next/start.js --name my-project-frontend
|
|||||||
|
|
||||||
Подробнее: [`docs/PROJECT_RULES.md`](docs/PROJECT_RULES.md)
|
Подробнее: [`docs/PROJECT_RULES.md`](docs/PROJECT_RULES.md)
|
||||||
|
|
||||||
|
## 🔧 Дополнительные инструменты
|
||||||
|
|
||||||
|
### Форматирование кода (Prettier)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd frontend
|
||||||
|
npm run format # Форматировать весь код
|
||||||
|
npm run format:check # Проверить форматирование
|
||||||
|
```
|
||||||
|
|
||||||
|
### Переменные окружения
|
||||||
|
|
||||||
|
Скопируйте `.env.example` файлы и заполните значения:
|
||||||
|
- `frontend/.env.example` → `frontend/.env.local`
|
||||||
|
- `backend/.env.example` → `backend/.env`
|
||||||
|
|
||||||
## 📝 Лицензия
|
## 📝 Лицензия
|
||||||
|
|
||||||
ISC
|
ISC
|
||||||
@ -144,3 +160,7 @@ ISC
|
|||||||
|
|
||||||
Создано на основе стандартов разработки DosAi
|
Создано на основе стандартов разработки DosAi
|
||||||
|
|
||||||
|
## 📚 Дополнительная информация
|
||||||
|
|
||||||
|
См. [`IMPROVEMENTS.md`](IMPROVEMENTS.md) для списка улучшений и рекомендаций.
|
||||||
|
|
||||||
|
|||||||
10
backend/middleware/.gitkeep
Normal file
10
backend/middleware/.gitkeep
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Middleware
|
||||||
|
|
||||||
|
Размещайте здесь middleware функции для Express.
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
- logger.js - логирование запросов
|
||||||
|
- errorHandler.js - обработка ошибок
|
||||||
|
- auth.js - аутентификация (если нужно)
|
||||||
|
- validate.js - валидация запросов (если нужно)
|
||||||
|
|
||||||
16
backend/middleware/errorHandler.js
Normal file
16
backend/middleware/errorHandler.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Middleware для обработки ошибок
|
||||||
|
const errorHandler = (err, req, res, next) => {
|
||||||
|
console.error('Error:', err);
|
||||||
|
|
||||||
|
const statusCode = err.statusCode || 500;
|
||||||
|
const message = err.message || 'Internal Server Error';
|
||||||
|
|
||||||
|
res.status(statusCode).json({
|
||||||
|
success: false,
|
||||||
|
error: message,
|
||||||
|
...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = errorHandler;
|
||||||
|
|
||||||
21
backend/middleware/logger.js
Normal file
21
backend/middleware/logger.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Middleware для логирования запросов
|
||||||
|
const logger = (req, res, next) => {
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
const method = req.method;
|
||||||
|
const url = req.url;
|
||||||
|
const ip = req.ip || req.connection.remoteAddress;
|
||||||
|
|
||||||
|
console.log(`[${timestamp}] ${method} ${url} - ${ip}`);
|
||||||
|
|
||||||
|
// Логируем время ответа
|
||||||
|
const start = Date.now();
|
||||||
|
res.on('finish', () => {
|
||||||
|
const duration = Date.now() - start;
|
||||||
|
console.log(`[${timestamp}] ${method} ${url} - ${res.statusCode} (${duration}ms)`);
|
||||||
|
});
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = logger;
|
||||||
|
|
||||||
46
backend/routes/example.js
Normal file
46
backend/routes/example.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Пример файла с роутами
|
||||||
|
// Используйте эту структуру для организации API endpoints
|
||||||
|
|
||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// GET endpoint
|
||||||
|
router.get('/hello', (req, res) => {
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: 'Hello from example route!',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// POST endpoint с валидацией
|
||||||
|
router.post('/data', (req, res) => {
|
||||||
|
try {
|
||||||
|
const { name, value } = req.body;
|
||||||
|
|
||||||
|
// Простая валидация
|
||||||
|
if (!name || !value) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Name and value are required',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработка данных
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
processed: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: err.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
|
|
||||||
@ -1,10 +1,13 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
|
const logger = require('./middleware/logger');
|
||||||
|
const errorHandler = require('./middleware/errorHandler');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3001;
|
const PORT = process.env.PORT || 3001;
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
|
app.use(logger);
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
@ -20,9 +23,13 @@ app.use((req, res, next) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Тестовый endpoint
|
// Health check endpoint
|
||||||
app.get('/api/health', (req, res) => {
|
app.get('/api/health', (req, res) => {
|
||||||
res.json({ status: 'ok', message: 'Server is running' });
|
res.json({
|
||||||
|
status: 'ok',
|
||||||
|
message: 'Server is running',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Пример API endpoint
|
// Пример API endpoint
|
||||||
@ -35,6 +42,21 @@ app.post('/api/example', (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Подключение роутов (пример)
|
||||||
|
// const exampleRoutes = require('./routes/example');
|
||||||
|
// app.use('/api/example', exampleRoutes);
|
||||||
|
|
||||||
|
// Обработка 404
|
||||||
|
app.use((req, res) => {
|
||||||
|
res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
error: 'Route not found',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обработка ошибок (должен быть последним middleware)
|
||||||
|
app.use(errorHandler);
|
||||||
|
|
||||||
// Запуск сервера
|
// Запуск сервера
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`🚀 Server is running on http://localhost:${PORT}`);
|
console.log(`🚀 Server is running on http://localhost:${PORT}`);
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import ExampleComponent from '@/components/ExampleComponent';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen py-8">
|
<div className="min-h-screen py-8">
|
||||||
@ -17,6 +19,10 @@ export default function Home() {
|
|||||||
<li>Начните разработку!</li>
|
<li>Начните разработку!</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-8">
|
||||||
|
<ExampleComponent />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
70
frontend/components/ExampleComponent.tsx
Normal file
70
frontend/components/ExampleComponent.tsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Пример React компонента с использованием API
|
||||||
|
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { apiRequest } from '@/lib/api';
|
||||||
|
|
||||||
|
interface ApiData {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ExampleComponent() {
|
||||||
|
const [data, setData] = useState<ApiData | null>(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const handleFetch = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await apiRequest<ApiData>('example', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
name: 'Test',
|
||||||
|
value: '123',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.success && response.data) {
|
||||||
|
setData(response.data);
|
||||||
|
} else {
|
||||||
|
setError(response.error || 'Unknown error');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setError(err instanceof Error ? err.message : 'Failed to fetch data');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-4 bg-gray-700 rounded-lg">
|
||||||
|
<h2 className="text-xl font-semibold mb-4">Пример компонента</h2>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleFetch}
|
||||||
|
disabled={loading}
|
||||||
|
className="px-4 py-2 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-600 rounded"
|
||||||
|
>
|
||||||
|
{loading ? 'Загрузка...' : 'Получить данные'}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="mt-4 p-2 bg-red-800 text-red-200 rounded">
|
||||||
|
Ошибка: {error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{data && (
|
||||||
|
<div className="mt-4 p-2 bg-green-800 text-green-200 rounded">
|
||||||
|
<p>Name: {data.name}</p>
|
||||||
|
<p>Value: {data.value}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@ -6,7 +6,9 @@
|
|||||||
"dev": "next dev --turbopack",
|
"dev": "next dev --turbopack",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint",
|
||||||
|
"format": "prettier --write .",
|
||||||
|
"format:check": "prettier --check ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
@ -22,7 +24,8 @@
|
|||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
"eslint-config-next": "15.3.3",
|
"eslint-config-next": "15.3.3",
|
||||||
"@eslint/eslintrc": "^3"
|
"@eslint/eslintrc": "^3",
|
||||||
|
"prettier": "^3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user