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.

8.9 KiB

Структура проекта 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, безопасность

📊 Схема базы данных (кратко)

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:

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