Техническая документация
Документ для ИТ-специалистов: из чего состоит «Гараж», как его развернуть, настроить и связать с другими системами.
Назначение и состав
«Гараж» — веб-приложение для учёта корпоративного автопарка. Пользователи работают в веб-интерфейсе; данные из внешних сервисов загружают фоновые команды по расписанию; изменения данных публикуются в шину событий.
| Часть | Назначение |
|---|---|
| Веб-интерфейс | учёт автомобилей, журналы событий, счета, отчёты в Excel |
| API | чтение данных об автомобилях и полисах другими системами |
| Команды интеграций | загрузка данных из внешних сервисов, уведомления и сводки |
| Шина событий | публикация изменений в Apache Kafka |
Технологии
| Компонент | Версия |
|---|---|
| Python | 3.10 |
| Django | 4.2 |
| Django REST Framework | 3.15 |
| СУБД | PostgreSQL 14 (для разработки — SQLite) |
| Сервер приложений | gunicorn за nginx |
| Шина событий | Apache Kafka (SASL_SSL) |
| Отчёты | XlsxWriter |
Требования к серверу
- Linux-сервер (Ubuntu 22.04 или новее), 2 ядра, 4 ГБ памяти, 20 ГБ диска — для парка до нескольких сотен автомобилей;
- PostgreSQL 14;
- nginx с сертификатом TLS;
- исходящий доступ в интернет к подключаемым сервисам;
- планировщик задач (cron или таймеры systemd).
Установка
apt update
apt install postgresql nginx python3.10 python3.10-venv -y
База данных и пользователь:
CREATE DATABASE garagedb;
CREATE USER garage WITH ENCRYPTED PASSWORD '<пароль>';
GRANT ALL PRIVILEGES ON DATABASE garagedb TO garage;
Приложение:
python3.10 -m venv venv
venv/bin/pip install -r requirements.txt
cp env.example.py env.py # и заполнить, см. «Конфигурация»
venv/bin/python manage.py migrate
venv/bin/python manage.py collectstatic
venv/bin/python manage.py createsuperuser
Проверочный запуск:
venv/bin/gunicorn PGcars.wsgi --bind 0:8000
В рабочем режиме gunicorn запускается службой systemd за nginx; nginx отдаёт каталоги static/ и media/.
Конфигурация
Все настройки и секреты — в файле env.py в корне проекта. Он не хранится в репозитории и создаётся из шаблона env.example.py. При запуске система сверяет env.py с шаблоном и не стартует, если какой-то переменной не хватает, — в сообщении перечислены недостающие имена.
| Группа | Переменные |
|---|---|
| Общие | DEBUG, ALLOWED_HOSTS, HOST, USE_TZ |
| Название | PRODUCT_NAME, COMPANY_NAME, CONTRACT_OWNERS |
| База данных | DB_ENGINE, DB_NAME, DB_HOST, DB_PORT, POSTGRES_USER, POSTGRES_PASSWORD |
| Почта | EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, ALERT_EMAILS |
| Мессенджер | MAX_TOKEN, MAX_CHAT_ALERT, MAX_CHAT_NOTIFICATION |
| Топливные карты | PPR_API_NEW — учётные данные кабинетов |
| Спутниковый мониторинг | KGK_TOKENS — токены кабинетов |
| 1С | ONEC_URL, ONEC_LOGIN, ONEC_PASSWORD, ONEC_ALERT_EMAILS |
| Сервис-деск | M4_CREATE_TASKS, M4_API_URL, M4_AUTH_URL, M4_USERNAME, M4_PASSWORD |
| Платные дороги | CKAD_API_URL, CKAD_ACCOUNTS |
Параметры подключения к Kafka — в отдельном файле kafka/config.py: адреса брокеров, учётные данные SASL, каталог сертификатов, тема.
Пользователи и права
Используется стандартная модель прав Django: пользователи, группы и права на каждую модель — просмотр, добавление, изменение, удаление. Права назначаются группам в веб-интерфейсе администратором.
Для счетов есть дополнительные роли, от которых зависит набор доступных полей: базовое редактирование, согласование директором по безопасности, финансовые поля.
Пароли хранятся в виде хешей (PBKDF2). Вход в веб-интерфейс — по сессии, защита форм от CSRF включена.
Интеграции
Загрузка данных выполняется командами manage.py, которые запускает планировщик. Ошибка в одном источнике не останавливает остальные и попадает в сводку.
| Сервис | Что загружается | Периодичность |
|---|---|---|
| Оператор топливных карт | карты, транзакции, штрафы; привязка карт к автомобилям | раз в день |
| Спутниковый мониторинг | трекеры, одометр, суточные пробеги | раз в день; одометр — чаще |
| 1С:Бухгалтерия (OData) | основные средства и амортизация | раз в месяц |
| Сервис-деск | сотрудники; создание заявок по ДТП, ТО, полисам | раз в день и по событиям |
| Оператор платных дорог | проезды и постановления | раз в день |
Команды
| Команда | Назначение |
|---|---|
ppr daily |
карты, транзакции и штрафы по всем кабинетам, сводка ответственным |
ppr bills |
счета на новые штрафы |
kgk daily |
одометр, пробеги за 7 дней, проверки за вчера и сводка |
kgk odometer --update-only |
только обновление одометра |
kgk checks |
проверки за день по данным в базе, без рассылки |
onec depreciation |
амортизация за последние закрытые месяцы |
notifications |
напоминания о ТО, полисах и техосмотрах |
outbox |
отправка накопленных событий в Kafka |
cleanup_outbox |
удаление давно отправленных событий |
Пример расписания:
0 7 * * * manage.py ppr daily
30 7 * * 4 manage.py ppr bills --offset 4
0 6 * * * manage.py kgk daily
0 8 * * * manage.py notifications
*/5 * * * * manage.py outbox
0 5 28 * * manage.py onec depreciation
Особенности
- Сопоставление автомобилей между системами идёт по госномеру, приведённому к единому виду.
- Лимит запросов. Если у сервиса платное API, каждый запрос учитывается в журнале; при исчерпании лимита загрузка останавливается, а ручные запуски оставляют запас для планового.
- Повторы. Клиенты повторяют запросы при обрыве соединения и таймауте; ответы с ошибкой не повторяются.
- 1С читается через стандартный интерфейс OData, только на чтение; изменений в базе 1С система не делает.
API
API предназначен для чтения данных другими системами компании. Все методы — GET, ответы в JSON.
| Адрес | Ответ |
|---|---|
/api/cars/ |
список госномеров автомобилей |
/api/car/<госномер>/ |
данные автомобиля |
/api/polis/<госномер>/ |
действующий полис ОСАГО |
/api/sts/<госномер>/ |
файл СТС |
/api/osago/<госномер>/ |
файл действующего полиса ОСАГО |
Методы, возвращающие JSON, требуют авторизации — Basic или сессии веб-интерфейса. Файлы отдаются по прямой ссылке; доступ к ним ограничивается на уровне сети или nginx.
Пример:
curl -u user:password https://garage.example.com/api/car/A123BC77/
{
"VINnumber": "XTA21901000000000",
"model": "LADA GRANTA",
"type_car": "Легковой комби (хэтчбек)",
"car_category": "B/M1",
"year": 2024,
"color_name": "Белый",
"sts_serial": "99 12",
"sts_number": "345678",
"sts_start_date": "15.03.2024",
"leasing_agreement": "ЛД-2024/0153",
"lising_org": "ООО «Вектор Лизинг»"
}
Шина событий
Изменения данных публикуются в Apache Kafka по схеме transactional outbox:
- При создании, изменении или удалении записи событие сохраняется в таблицу
Outboxвместе с самим изменением. - Команда
outboxпачками отправляет события в Kafka.
Формат события:
{
"model": "garage.Car",
"action": "UPDATE",
"data": { "id": 15, "grz": "A123BC77", "odometer": 84120 }
}
action принимает значения CREATE, UPDATE, DELETE; связи передаются идентификаторами.
Гарантии доставки:
- события отправляются строго в порядке появления;
- отправленным считается только непрерывное начало пачки, доставленное без ошибок;
- при ошибке отправка останавливается и повторяется со следующего запуска.
Событие может прийти повторно, поэтому получатель должен быть идемпотентным. Сохранение записи без изменений события не создаёт.
Данные
| Область | Основные сущности |
|---|---|
| Автопарк | автомобиль, модель, топливная карта, сотрудник, автосервис, организация, дивизион, регион, офис |
| Журналы | полис, лизинг, транспортный налог, ТО, техосмотр, ДТП, штраф, транзакция, суточный пробег, смены водителя, организации и региона |
| Счета и расходы | счёт, статья затрат, подразделение, юридическое лицо |
| Бухгалтерия | основное средство, амортизация за месяц |
| Платные дороги | проезд, постановление |
Файлы документов (СТС, ПТС, полисы, акты ТО, договоры) хранятся на диске сервера в каталоге media/.
Резервное копирование
Копировать нужно три вещи: базу данных, каталог media/ и файлы конфигурации (env.py, kafka/config.py, сертификаты).
# дамп базы
pg_dump -U garage -Fc garagedb > garagedb_$(date +%F).dump
# восстановление
pg_restore -U garage -d garagedb --clean garagedb_2026-01-15.dump
Рекомендуется ежедневный дамп с хранением за месяц и копированием на другой сервер.
Обновление
git pull
venv/bin/pip install -r requirements.txt
venv/bin/python manage.py migrate
venv/bin/python manage.py collectstatic --noinput
systemctl restart garage
Перед обновлением сделайте дамп базы. Если в новой версии появились переменные конфигурации, добавьте их в env.py до обновления кода — иначе система не запустится.
Безопасность
- доступ к веб-интерфейсу — только по HTTPS, после входа;
- секреты внешних систем хранятся в
env.pyна сервере и не попадают в репозиторий; - значения из внешних систем в отчётах Excel не превращаются в формулы и ссылки;
- интеграции с 1С работают только на чтение;
- журнал запросов к платным API ведётся в базе.