ViKo System
Модульный backend для грузоперевозок, автосервиса, финансов, CMS, маркетинга, склада, трекинга и др. по ТЗ.
Основной запуск: Python + локальный PostgreSQL (localhost:5432), без Docker.
Stack
- Python 3.12
- FastAPI
- PostgreSQL (локально)
- SQLAlchemy 2.0, Alembic, Pydantic v2
- JWT (python-jose), passlib/bcrypt
- WebSocket, openpyxl, reportlab; APScheduler (фон: опрос трекеров каждые 30 с, плановый бэкап по расписанию из БД), qrcode
- По ТЗ основной путь без Docker — только Python и локальный PostgreSQL.
Project Structure
-
app/core— конфиг, БД, auth, idempotency, seed, CompanyDetails, назначения водителей, акты приёма-передачи, ежедневные осмотры, документы сотрудников, HATEOAS-хелпер, планировщик -
app/modules/logistics— заказы, рейсы, аренда -
app/modules/service— клиенты, проблемы, наряды, осмотры, чек-листы, логи, заявки с QR -
app/modules/accounting— счета, платежи, расходы, P&L, CashAccount / CashFlow / DailyBalance, журнал ДДСGET /finance/money-journal(периоды день/неделя/месяц/год, печать PDF), синхронизация проводок из платежей, расходов и зарплаты вcash_flows -
app/modules/payroll— ставки, учёт времени, транзакции, SalaryComponent / SalaryRule -
app/modules/cms— сайты, страницы, услуги, тарифы, акции, отзывы, FAQ, CompanyAdvantage, PartnerCertificate -
app/modules/notifications— in-app, шаблоны, SmsLog, правила и подписки -
app/modules/reports— шаблоны, документы, PrintTemplate -
app/modules/internship— стажировки: статусы, CRUD, этапы, оценки, наставничество, шаблоны, назначение ТС (/internships/{id}/car-assignments) -
app/modules/marketing+corporate— лиды, B2B, рассылки (dispatch заданий — фиксацияsent_at/счётчиков), промо, реферальные настройки (чтение диспетчером, правка — админ) -
app/modules/uniform— спецодежда: номенклатура, выдачи/возврат, поставки, списания (/admin/uniform/write-offs) -
app/modules/tracking— трекеры, геозоны (каркас) -
app/modules/backup— настройки в БД, история; POST /admin/backup/run —pg_dump -Fc(PostgreSQL), горячая копия файла (SQLite на диске) или симуляция; GET /admin/backup/status, GET /admin/backup/files/{id}, GET /admin/backup/history/{id}/listing (pg_restore -l); восстановление: POST /admin/backup/restore/run (pg_restoreили замена файла SQLite, аварийный снимок перед операцией); плановый бэкап по cron приis_enabled; UI:/backup -
app/modules/warehouse— склады, зоны хранения, StockPart, движения (receipt/issue/adjust/reserve/release), контроль низкого остатка -
app/modules/equipment— учёт инструмента и оборудования (список, карточка, создание) -
app/modules/public— публичные заявки без JWT
Полное ТЗ (все эндпоинты из п.3) наращивается итерациями: схема БД и заготовки роутов заложены; бизнес-логика части разделов — stub.
Run
Локально без Docker
-
Установите PostgreSQL (например 16), запустите службу.
-
Создайте пользователя и базу (пароль
vikoдолжен совпадать с.env):psql -U postgres -f scripts/create_local_db.sqlЕсли
psqlне в PATH, используйте SQL Shell (psql) из меню Пуск или pgAdmin → Query Tool и выполните команды изscripts/create_local_db.sqlвручную. -
Скопируйте
.env.exampleв.env. В.envдля локального запуска должно быть
DATABASE_URL=postgresql://viko:viko@localhost:5432/viko(в.env.exampleэто уже так по умолчанию). -
Python 3.12 (рекомендуется). На Python 3.14+ под Windows часто нет готовых сборок
psycopg2-binaryиpydantic-core— установка потребует Visual Studio Build Tools с компонентом «Разработка классических приложений на C++». Чтобы не возиться с компилятором, поставьте 3.12 с python.org и создайте.venvим.Зависимости:
Проще всего — один скрипт (из папки проекта; активация
.venvне нужна):cd "c:\projects\viko-system 2" powershell -ExecutionPolicy Bypass -File .\scripts\run_local.ps1Вручную без
Activate.ps1(если скрипт не подошёл): сначала зайдите в каталог проекта, создайте venv и вызывайте всё черезpython.exeиз.venv:cd "c:\projects\viko-system 2" py -3.12 -m venv .venv .\.venv\Scripts\python.exe -m pip install -r requirements.txt .\.venv\Scripts\python.exe -m alembic upgrade head .\.venv\Scripts\python.exe -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000Если нет
py, замените первую строку на:python -m venv .venv -
Откройте
http://127.0.0.1:8000/docs.
Если ругается на Activate.ps1 — можно не активировать venv и использовать команды с .\.venv\Scripts\python.exe -m ..., как выше. Политика выполнения:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned.
Через Docker (если доступен)
- Скопировать
.env.exampleв.env, вDATABASE_URLуказать хостdb:
postgresql://viko:viko@db:5432/viko - Запустить:
docker compose up --build
Если установлен старый CLI, можно также docker-compose up --build.
Приложение будет доступно по http://localhost:8000.
Swagger:
http://localhost:8000/docs
Проверка БД:
-
GET /health— процесс жив -
GET /health/db— соединение с PostgreSQL
Migrations
Локально:
alembic upgrade head
Цепочка включает 20260410_0003_tz_schema_expand: создание новых таблиц и ALTER TABLE ... IF NOT EXISTS для расширения employees, cars, service_clients, work_orders, car_inspections, trips, reviews (PostgreSQL).
В Docker миграции запускаются при старте контейнера приложения (см. Dockerfile).
После обновления зависимостей: pip install -r requirements.txt (в т.ч. APScheduler, qrcode).
Test Data
При запуске uvicorn подставляются только категории расходов (seed_system_reference) — без демо-машин, тестовых сотрудников и контрагентов; удалённые записи не появляются снова.
Демо-данные (seed_initial_data с SEED_DEMO_DATA=true) используются в pytest и скриптах (scripts/shipment_bulk_form_smoke.py), не при обычном старте приложения.
Чтобы вручную или в тестах заполнить стенд демо-пользователями (телефоны 70000000001 … 70000000006, машины из seed.py, тестовые контрагенты), задайте:
SEED_DEMO_DATA=true
и вызовите seed_initial_data (как в tests/conftest.py).
После включения:
- admin:
70000000001 - dispatcher:
70000000002 - driver:
70000000003 - mechanic:
70000000004 - supplier_logist:
70000000005 - logist:
70000000006
Dev login code для всех этих пользователей:
1234
Резервные копии и восстановление после переустановки Windows
Почему «пропали» заказы и журнал ДДС, а сотрудники и машины есть.
После чистой установки PostgreSQL вы создаёте новую пустую базу (CREATE DATABASE), затем alembic upgrade head. Заказы, рейсы, проводки журнала и т.п. в ней изначально пусты.
Сотрудники и автомобили, которые вы видите сразу после старта, чаще всего приходят из демо-seed (app/core/seed.py при запуске приложения), а не из «старой» базы — это не восстановление, а шаблонные записи.
Восстановить «как было» можно только из резервной копии, например:
- файл
*.dump, снятый черезpg_dump -Fc(так делает встроенный модуль бэкапа приBACKUP_PG_DUMP_ENABLED=true, либо скрипт ниже); - старый каталог данных PostgreSQL с того же major-версии (сложнее и реже нужно);
- любой архив, который вы сохранили до переустановки ОС.
Если отдельной копии нет, восстановить историю заказов и движений денег технически не из чего — только заново вводить данные или подгружать их через имеющиеся импорты (см. ниже).
Автоматический снимок на диск (рекомендуется)
Из корня проекта (пароль БД берётся из DATABASE_URL в .env):
powershell -ExecutionPolicy Bypass -File .\scripts\backup_postgres.ps1
Файл появится в backups/ (каталог в .gitignore). Копируйте .dump на другой диск или в облако. В Планировщике заданий Windows можно вызывать этот скрипт, например, раз в сутки.
Встроенный UI и API бэкапа
В приложении: страница /backup, API POST /admin/backup/run. Для реального pg_dump в PostgreSQL в .env должно быть BACKUP_PG_DUMP_ENABLED=true (и настроен каталог в настройках бэкапа). Восстановление через API — только при явных флагах безопасности в .env (BACKUP_RESTORE_ENABLED / BACKUP_PG_RESTORE_ENABLED), см. .env.example.
Дополнительно в этом модуле:
-
Проверка после копии (
BACKUP_VERIFY_AFTER_RUN): для PostgreSQL вызываетсяpg_restore -l, для SQLite —PRAGMA integrity_check; при ошибке проверки файл копии всё равно сохраняется, детали — в полеbackup_metaзаписи журнала. -
Архив
generated/: в настройках бэкапа можно включить упаковку каталогаGENERATED_DIRв ZIP рядом с дампом; скачивание:GET /admin/backup/files/{id}?artifact=generated. -
Минимум свободного места:
BACKUP_MIN_FREE_DISK_MB(0 = не проверять). - Плановый бэкап: после сохранения настроек расписание перечитывается планировщиком (без обязательного перезапуска uvicorn).
- Параллельный запуск копии и восстановления с одного процесса блокируется ответом
409 backup_or_restore_busy(в т.ч. между разными администраторами).
Ручное восстановление из *.dump (кратко)
Остановите приложение. Под суперпользователем PostgreSQL пересоздайте базу viko (или восстановите в новое имя и поменяйте DATABASE_URL), затем:
pg_restore -h localhost -p 5432 -U postgres -d viko --no-owner --role=viko путь\к\файлу.dump
Точные ключи (--clean, владелец объектов) зависят от вашей политики; при ошибках прав смотрите лог pg_restore.
Подгрузка данных без полного дампа
-
Журнал ДДС: в веб-интерфейсе учёта — импорт Excel, эндпоинты
GET /finance/money-journal/import-hintsиPOST /finance/money-journal/import-excel(формат описан в подсказках). -
Заказы: массовая загрузка логистом —
POST /logist/orders/bulk(.xlsx, см. README в блоке Assumptions / Limitations иbulk_uploadв коде).
Переменные окружения (опционально)
-
PDF с кириллицей (
журнал ДДС,заказ-наряд): используются системные TTF (Windows: Arial/Segoe; Linux: DejaVu/Liberation) или файлstatic/fonts/DejaVuSans.ttfв корне проекта. -
Отправка заказ-наряда по e-mail (
POST /work-orders/{id}/send-to-client): задайтеSMTP_HOST,SMTP_PORT(по умолчанию 587), при необходимостиSMTP_USER,SMTP_PASSWORD,SMTP_FROM_EMAIL,SMTP_USE_TLS(по умолчаниюtrue). БезSMTP_HOSTписьмо не уходит (остальные каналы — как реализованы в коде). -
OCR чека (
POST /driver/receipt-ocr):pip install pytesseract Pillowуже вrequirements.txt; нужен установленный Tesseract вPATHи языковые данные (rus,engилиrus+eng).
Main Endpoint Groups
/auth/login-
/users,/employees,/cars,/counterparties,/counterparty-logists -
/orders,PATCH /orders/{id}(черновик / согласование),/trips,/orders/public,/logist/orders,/logist/orders/bulk,/dispatcher/orders/* -
/supplier/rental-requests, approve/reject,/supplier/rental-requests/{id},/driver/trips,/driver/issues,/issues,/work-orders - Списки: query-параметры
limit(1–200, по умолчанию 50) иoffset(по умолчанию 0) на основныхGET-списках (в т.ч. core: пользователи, сотрудники, машины, контрагенты; заказы, рейсы, финансы, сервис, payroll, уведомления). - Логистика: назначение машины только для заказа в статусе
approvedи без уже созданного активного рейса (отменённые рейсы не мешают повторному назначению); согласование — изdraft/pending_approval; отклонение заказа недоступно для уже назначенных/завершённых. - Отмена:
POST /dispatcher/trips/{id}/cancel(диспетчер/админ) — рейс вcancelled, заказ изcar_assignedвозвращается вapproved, связанные заявки аренды вpending/approved→cancelled.POST /supplier/rental-requests/{id}/cancel— отмена только pending (поставщик по своей заявке или диспетчер/админ). - CORS: переменная
CORS_ORIGINS—*или список через запятую, напримерhttps://vikoauto.ru,https://perevoz35.ru. - Сервис:
POST/GET /parts, строки запчастей в заказ-нарядеPOST/GET /work-orders/{id}/parts, осмотрPOST /work-orders/{id}/inspection; списание со склада при добавлении запчасти в наряд. -
/payroll/*— ставки, учёт времени, начисления, подтверждения зарплаты -
/invoices,/payments,/expenses(списки иGETпоid),/reports/pnl* -
/orders/{id},/trips/{id},/mechanic/issues/{id},/work-orders/{id} -
/cms/*,/admin/cms/* -
/notifications/send,/notifications/me,PATCH /notifications/{id}/read,/ws/notifications -
/reports/*,/admin/reports/templates
Test Scenario
Интеграционный сценарий:
python test_scenario.py
По умолчанию используется http://localhost:8000.
Юнит/интеграционные проверки API на SQLite in-memory:
pytest tests -q
Assumptions / Limitations
- Авторизация по коду
1234реализована как dev-only MVP. - Email / SMS / push выполнены как stub-каналы, основная рабочая реализация - in-app уведомления.
-
bulk upload: для.xlsxпервая строка — заголовки колонокsource,destination, опциональноweight_kg,volume_m3,client_phone,client_price. Иные расширения — позже. - PDF и Excel генерируются в простом базовом формате.
- P&L в MVP считается как
payments - expenses. -
Idempotency-Keyподдержан дляdriver-confirm/complete trip и создания issue. -
payroll: REST API для ставок, учёта времени, начислений и подтверждений зарплаты (admin/dispatcher); расчёт ведомостей можно наращивать отдельно. - Админский CMS CRUD сделан в MVP-формате: полный рабочий create/list плюс generic update/delete.
-
WorkOrderиз online appointment создается в упрощенном виде с машиной по умолчаниюcar_id=1. - Логист контрагента в
GET /ordersиGET /orders/{id}видит заказы, привязанные к его контрагентам (counterparty_logists), и заказы, созданные им самим. - В seed добавлены демо-связи: поставщик и логист привязаны к демо-контрагентам; у логиста — контрагент
Logist Partner Demo.