You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
8.9 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Структура проекта Polotsk Transit API
## 📁 Обзор директорий
```
polotsk-transit-api/
├── backend/ # Node.js API сервер
│ ├── src/
│ │ ├── config/ # Конфигурация (DB, Redis, Logger)
│ │ ├── controllers/ # Бизнес-логика
│ │ │ ├── routesController.js # Управление маршрутами
│ │ │ ├── stopsController.js # Управление остановками + PostGIS
│ │ │ ├── etaController.js # Расчет ETA
│ │ │ └── syncController.js # Offline синхронизация
│ │ ├── middleware/ # Middleware (Auth, Rate Limiting)
│ │ ├── routes/ # Express маршруты
│ │ └── index.js # Точка входа
│ ├── migrations/ # SQL миграции (PostGIS схема)
│ ├── package.json
│ └── Dockerfile
├── frontend/ # React админ-панель
│ ├── src/
│ │ ├── components/ # React компоненты
│ │ │ ├── RouteForm.jsx # Форма маршрута
│ │ │ └── StopForm.jsx # Форма остановки
│ │ ├── pages/ # Страницы
│ │ │ ├── Dashboard.jsx # Главная страница
│ │ │ ├── RoutesPage.jsx # Управление маршрутами
│ │ │ ├── StopsPage.jsx # Остановки + карта Leaflet
│ │ │ └── SchedulesPage.jsx # Расписания (заглушка)
│ │ ├── services/ # API клиент
│ │ ├── App.jsx # Главный компонент + роутинг
│ │ ├── main.jsx # Точка входа
│ │ └── index.css # Tailwind стили
│ ├── package.json
│ ├── vite.config.js
│ └── Dockerfile
├── nginx/ # Reverse proxy конфигурация
│ └── nginx.conf # Nginx для API + Admin + SSL
├── docker-compose.yml # Оркестрация всех сервисов
├── .env.example # Шаблон переменных окружения
├── .gitignore
├── README.md # Полная документация
└── QUICKSTART.md # Быстрый старт
```
## 🎯 Ключевые файлы
### Backend
**Конфигурация:**
- `backend/src/config/database.js` - PostgreSQL connection pool
- `backend/src/config/redis.js` - Redis клиент для кеширования
- `backend/src/config/logger.js` - Winston logger
**Контроллеры:**
- `backend/src/controllers/routesController.js` - CRUD маршрутов + кеширование
- `backend/src/controllers/stopsController.js` - CRUD остановок + PostGIS геопоиск
- `backend/src/controllers/etaController.js` - Умный расчет времени прибытия
- `backend/src/controllers/syncController.js` - Полная и инкрементальная синхронизация
**Middleware:**
- `backend/src/middleware/auth.js` - API key аутентификация
- `backend/src/middleware/rateLimiter.js` - Rate limiting с Redis
**Миграции:**
- `backend/migrations/001_init.sql` - Полная схема БД с PostGIS
### Frontend
**Страницы:**
- `frontend/src/pages/Dashboard.jsx` - Статистика и быстрый старт
- `frontend/src/pages/RoutesPage.jsx` - Управление маршрутами с карточками
- `frontend/src/pages/StopsPage.jsx` - Карта Leaflet + список остановок
- `frontend/src/pages/SchedulesPage.jsx` - Заглушка для будущего функционала
**Компоненты:**
- `frontend/src/components/RouteForm.jsx` - Форма создания/редактирования маршрута
- `frontend/src/components/StopForm.jsx` - Форма создания/редактирования остановки
**API сервис:**
- `frontend/src/services/api.js` - Axios клиент со всеми endpoints
### Инфраструктура
**Docker:**
- `docker-compose.yml` - 5 сервисов (PostgreSQL, Redis, Backend, Frontend, Nginx)
- `backend/Dockerfile` - Node.js production образ
- `frontend/Dockerfile` - Multi-stage build с Nginx
**Nginx:**
- `nginx/nginx.conf` - Reverse proxy с SSL, rate limiting, безопасностью
## 🔧 Основные технологии
| Компонент | Технология | Назначение |
|-----------|------------|------------|
| API Server | Express.js | REST API |
| База данных | PostgreSQL + PostGIS | Хранение данных + геопространственные запросы |
| Кеш | Redis | Кеширование + pub/sub для WebSocket |
| Frontend | React + Vite | Админ-панель |
| Карты | React Leaflet | Интерактивная карта |
| Стили | Tailwind CSS | Быстрая разработка UI |
| Контейнеризация | Docker Compose | Оркестрация сервисов |
| Reverse Proxy | Nginx | SSL, rate limiting, безопасность |
## 📊 Схема базы данных (кратко)
```sql
routes -- Маршруты (номер, название, тип, цвет)
stops -- Остановки (название, GEOGRAPHY(Point), адрес)
route_stops -- М:М связь маршрутов и остановок (с sequence и time_offset)
schedules -- Расписания (departure_times[], day_type)
vehicles -- Транспортные средства
historical_delays -- Статистика задержек для умного ETA
alerts -- Уведомления и алерты
api_keys -- API ключи для аутентификации
sync_log -- Лог изменений для offline синхронизации
```
## 🚀 Что уже работает
✅ Полный REST API
✅ CRUD для маршрутов и остановок
✅ PostGIS геопространственные запросы (ближайшие остановки)
✅ Расчет ETA на основе расписания + исторических задержек
✅ Offline синхронизация (полная и инкрементальная)
Веб админ-панель с картой
✅ Docker deployment
✅ API key аутентификация
✅ Rate limiting
✅ Кеширование через Redis
✅ Логирование
## 📝 Что добавить в будущем
**Версия 2.0 (Краудсорсинг):**
- [ ] WebSocket для реалтайм GPS
- [ ] Endpoint для приема GPS от пользователей
- [ ] Агрегация и фильтрация GPS данных
- [ ] Функция "Я еду в маршруте"
**Версия 3.0 (Продвинутые функции):**
- [ ] IoT GPS-трекеры
- [ ] ML для предсказания задержек
- [ ] Push уведомления
- [ ] Детальная аналитика
## 💡 Советы по развертыванию
1. **Обязательно смените пароли** в `.env` перед продакшеном
2. **Используйте Cloudflare Tunnel** для скрытия домашнего IP
3. **Настройте SSL** через Let's Encrypt или Cloudflare
4. **Включите fail2ban** для защиты от брутфорса
5. **Настройте бэкапы** PostgreSQL (pg_dump + cron)
6. **Мониторинг** через Docker stats или Prometheus
## 🎓 Интеграция с мобильными приложениями
Используйте эндпоинт `/api/v1/sync` для offline-first подхода:
1. При первом запуске - полная синхронизация (без `lastSync`)
2. При последующих - инкрементальная (с `lastSync=timestamp`)
3. Храните данные локально (SQLite, Realm, Core Data)
4. Обновляйте в фоне каждые 5-10 минут
Пример для iOS:
```swift
func syncData() async {
let lastSync = UserDefaults.standard.object(forKey: "lastSync") as? Date
let params = lastSync != nil ? ["lastSync": ISO8601DateFormatter().string(from: lastSync!)] : [:]
let data = try await api.get("/sync", params: params)
await database.updateLocalData(data)
UserDefaults.standard.set(Date(), forKey: "lastSync")
}
```
---
**Создано для Полоцка 🇧🇾 | MIT License**