Skip to content

MikhailPI1/CODD_web_site

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🚦 Информационная система для ЦОДД Смоленск

Python PostgreSQL FastAPI SQLAlchemy Pandas JavaScript React Docker

В рамках хакатона Smolathon 2025 команда Сет представляет комплексное решение информационной системы для Центра организации дорожного движения (ЦОДД) г. Смоленск.

Проект влючает в себя фронтенд сайта ЦОДД, модульную систему для создания и редактирования статических и динамических страниц редактором из личного кабинета, инструменты доступа к открытой статистике и платформу для хранения и анализа данных из архива и базы данных, поддерживающую сравнение и прогнозирование из многих источников одновременно.

Поддерживаются любые типы статистики с возможностью представления их в виде шаблонов и валидацией при загрузке новых данных.

В основе лежит бекенд на python с использованием FastAPI и SQLAlchemy. В качестве базы данных используется PostgreSQL. В основе платформы анализа данных лежат пакеты pandas, scikit-learn и Prophet. Фронтенд написан с использованием React. Итоговое решение представлено в виде Docker-контейнера.


📊 Архитектура данных

В системе выделены три основных блока:

  1. Системные данные

    • Пользователи, роли, права доступа
    • Разделы сайта и посты, сохраняемые в JSON
  2. Файловая система

    • Загрузка и хранение документов
    • Поддержка форматов: изображения и видео, DOC, PDF, CSV, XLSX
    • Редактирование контента в удобном редакторе WYSIWYG
  3. Статистические данные

    • Создание гибких шаблонов для разных видов статистики
    • Реестр баз данных с проверкой загружаемой информации и настройкой публичного доступа

🗄️ Диаграмма базы данных

---
config:
  layout: elk
---
erDiagram
	direction TB
	StatsDBRegistry {
		INTEGER id PK ""  
		VARCHAR db_name  ""  
		VARCHAR display_name ""
		INTEGER templateid FK ""  
		TIMESTAMP created_at  ""  
		INTEGER created_by FK ""  
		TIMESTAMP updated_at  ""  
		INTEGER updated_by FK ""  
		BOOLEAN is_public  ""  
	}
	Fines {
		INTEGER id PK ""  
		INTEGER violations_count  ""  
		INTEGER fines_count  ""  
		NUMERIC fines_sum  ""  
		NUMERIC fines_collected_sum  ""  
	}
	Evacuations {
		INTEGER id PK ""  
		INTEGER evacuators_count  ""  
		INTEGER call_count  ""  
		INTEGER evacuations_count  ""  
		NUMERIC collected_sum  ""  
	}
	EvacuationRoutes {
		INTEGER id PK ""  
		VARCHAR month  ""  
		VARCHAR route  ""  
	}
	Crossings {
		INTEGER id PK ""  
		VARCHAR address  ""  
		VARCHAR ppid  ""  
	}
	Templates {
		INTEGER id PK ""  
		VARCHAR template_name  ""  
		TEXT fields_db  ""  
		TEXT field_types  ""  
		TEXT fields_natural  ""  
	}
	Documents {
		INTEGER id PK ""  
		VARCHAR filename  ""  
		VARCHAR original_name  ""  
		INTEGER file_size  ""  
		TIMESTAMP uploaded_at  ""  
		INTEGER uploaded_by FK ""  
		VARCHAR document_type  ""  
	}
	Users {
		INTEGER id PK ""  
		VARCHAR first_name  ""  
		VARCHAR last_name  ""  
		VARCHAR middle_name  ""  
		VARCHAR role  ""  
		BOOLEAN is_active  ""  
		VARCHAR login  ""  
		VARCHAR password_hashed  ""  
	}
	TrafficLights {
		INTEGER id PK ""  
		VARCHAR ppid  ""  
		VARCHAR address  ""  
		VARCHAR traffic_light_type  ""  
		INTEGER installed_year  ""  
	}
	Sections {
		INTEGER id PK ""  
		VARCHAR name  ""  
		VARCHAR section_type  ""  
	}
	Throughput {
		INTEGER id PK ""  
		VARCHAR crossing  ""  
		INTEGER car_count  ""  
	}
	Posts {
		INTEGER id PK ""  
		VARCHAR name  ""  
		INTEGER sectionid FK ""  
		TEXT contents  ""  
		TIMESTAMP created_at  ""  
		INTEGER created_by FK ""  
		TIMESTAMP uploaded_at  ""  
		INTEGER uploaded_by FK ""  
	}

	Templates||--o{StatsDBRegistry:"id -> templateid"
	StatsDBRegistry||--||Fines:"db_name <-> ."
	StatsDBRegistry||--||Evacuations:"db_name <-> ."
	StatsDBRegistry||--||EvacuationRoutes:"db_name <-> ."
	StatsDBRegistry||--||Crossings:"db_name <-> ."
	StatsDBRegistry||--||TrafficLights:"db_name <-> ."
	StatsDBRegistry||--||Throughput:"db_name <-> ."
	Users||--o{Documents:"id -> uploaded_by"
	Sections||--o{Posts:"section_type -> sectionid"
	Users||--o{Posts:"created_by &lt;- id<br style='--tw-scale-x: 1; --tw-scale-y: 1; --tw-pan-x: ; --tw-pan-y: ; --tw-pinch-zoom: ; --tw-scroll-snap-strictness: proximity; --tw-gradient-from-position: ; --tw-gradient-via-position: ; --tw-gradient-to-position: ; --tw-ordinal: ; --tw-slashed-zero: ; --tw-numeric-figure: ; --tw-numeric-spacing: ; --tw-numeric-fraction: ; --tw-ring-inset: ; --tw-ring-offset-width: 0px; --tw-ring-offset-color: fl°fff¶ß --tw-ring-color: rgb(59 130 246 / .5); --tw-ring-offset-shadow: 0 0 fl°°0000¶ß --tw-ring-shadow: 0 0 fl°°0000¶ß --tw-shadow: 0 0 fl°°0000¶ß --tw-shadow-colored: 0 0 fl°°0000¶ß --tw-blur: ; --tw-brightness: ; --tw-contrast: ; --tw-grayscale: ; --tw-hue-rotate: ; --tw-invert: ; --tw-saturate: ; --tw-sepia: ; --tw-drop-shadow: ; --tw-backdrop-blur: ; --tw-backdrop-brightness: ; --tw-backdrop-contrast: ; --tw-backdrop-grayscale: ; --tw-backdrop-hue-rotate: ; --tw-backdrop-invert: ; --tw-backdrop-opacity: ; --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; --tw-contain-size: ; --tw-contain-layout: ; --tw-contain-paint: ; --tw-contain-style: ;'>updated_by &lt;- id"
	Users||--o{StatsDBRegistry:"created_by &lt;- id</br>updated_by &lt;- id"

Loading

📂 Работа с данными

Система поддерживает загрузку и обработку внешних данных из файлов:

  • CSV (.csv)
  • Excel (.xls, .xlsx)

Загруженные таблицы могут быть:

  • сохранены в файловой системе сервера,
  • проверены на корректность формата,
  • преобразованы в новые шаблоны,
  • проверены на соответствие шаблону с поиском наложений в общей базе данных,
  • выгружены в общую базу данных,
  • использованы на платформе аналитики в качестве источника,
  • выгружены за выбранный период в поддерживаемых форматах.

Это позволяет быстро подключать новые источники данных и расширять аналитические возможности системы без дополнительной разработки.


📰 Управление контентом

Система позволяет редакторам вести как динамические, так и статические разделы:

  • Динамические:

    • Новости
    • Проекты
    • События
    • Любые другие регулярно обновляемые материалы
  • Статические:

    • Команда
    • О нас
    • Контактная информация
    • Другие постоянные разделы

Редакторский интерфейс основан на WYSIWYG-редакторе.
Все тексты и структуры разделов сохраняются в формате JSON в файловой системе сервера, что облегчает управление и поддержку контента.


📈 Платформа аналитики

Платформа обеспечивает полный цикл работы с данными — от загрузки до прогнозирования:

  • Поддержка различных источников данных (CSV, XLS, XLSX)
  • Проверка и валидация входящих данных по шаблонам
  • Хранение данных в PostgreSQL с возможностью масштабирования
  • Визуализация данных на фронтенде (React + JS)

Функциональность:

  • 📊 построение интерактивных графиков и таблиц
  • 📈 прогнозирование по архивным и актуальным данным
  • 📂 сравнение и объединение данных из разных источников

Диаграммы DataFlow

Получение постов

flowchart LR
    Guest["Гость / Пользователь"] -- зайти на страницу --> Frontend["Frontend<br>React"]
    Frontend -- запрос статического раздела --> ContentSvc["Контент сервис"]
    ContentSvc -- ответ --> Frontend
    Frontend --> StaticSection["Статический раздел<br>например, контакты"] & DynamicSection["Динамический раздел<br>Новости / Проекты"] & SinglePost["Страница поста<br>"]
    StaticSection -- рендер --> Guest
    Frontend -- запрос динамического раздела первый --> ContentSvc
    DynamicSection -- рендер 5 --> Guest
    Guest -- клик 'показать ещё' --> Frontend
    Frontend -- "получить следующие пять, сдвиг = N" --> ContentSvc
    PostsStore["Posts<br>JSON / Posts БД"] --> ContentSvc
    Frontend -- добавить следующие --> DynamicSection
    Guest -- клик на пост --> Frontend
    Frontend -- "получить пост с id = x" --> ContentSvc
    SinglePost --> Guest
    ContentSvc --> PostsStore

     ContentSvc:::boxes
     PostsStore:::boxes
    classDef boxes fill:#111,stroke:#fff,color:#fff

Loading

Публикация постов для редактора:

flowchart TD
    Editor["Редактор"] --> Choice["Создать новую<br>или редактировать существующую?"] & Preview["Предпросмотр"]
    Choice --> NewPost["Создать новую статью"] & EditPost["Выбрать существующую статью"]
    NewPost --> OpenEditor["Открыть WYSIWYG-редактор"]
    EditPost --> OpenEditor
    OpenEditor --> EditContent["Ввести / редактировать контент<br>(текст, метаданные)"]
    EditContent --> UploadMedia["Загрузить файл<br>(изображение / документ)"] & Preview
    UploadMedia --> FileTypeCheck["Определить тип загружаемого файла"]
    FileTypeCheck -- media img, doc, pdf --> CloudDrive["Файловая система: сохраняет файл<br>возвращает удобный URL"]
    FileTypeCheck -- analytics csv, xls, xlsx --> AnalyticsBlocked["Загрузка аналитических файлов<br>недоступна для редактора"]
    CloudDrive --> InsertURL["Вставить URL в контент"]
    InsertURL --> EditContent
    Preview --> Validate["Проверка обязательных полей"]
    Validate -- Ошибка --> OpenEditor
    AnalyticsBlocked -. <br> .-> Editor
    Publish["Опубликовать → сохранить в Posts"] --> Site["Запись доступна на сайте (публично)"]
    Validate --> n1["Преобразовать в JSON"]
    n1 --> Publish

    n1@{ shape: rect}
     CloudDrive:::serviceNodes
     Publish:::serviceNodes
    classDef serviceNodes fill:#111,stroke:#fff,color:#fff
Loading

Платформа аналитики:

flowchart TD
    Analyst["Администратор"] --> Upload["Загрузить файл .csv / .xls / .xlsx"]
    Upload --> AnalyticsRecv["Платформа аналитики: прием файла"] & StoreAnalytics["Хранение в файловой системе<br>"]
    AnalyticsRecv --> Decision{"Запись в основную БД?"}
    TemplateSel["Выбор шаблона<br>или создание нового"] --> FieldMap["Авто или ручное сопоставление полей"]
    FieldMap --> Validate["Валидация по шаблону"]
    Validate -- Ошибка --> AnalyticsRecv
    ImportDB["Импорт в Postgres<br>"] --> Visualize["Визуализация / Сравнение / Экспорт"]
    UpdateRegistry["Обновление реестра Stats Registry"] --> ImportDB
    Decision -- Нет --> StoreAnalytics
    StoreAnalytics --> Visualize
    Visualize -- можно брать данные из: --> VisualData["Основной БД подтверждённых данных или из файловой системы"]
    VisualData --> Visualize
    CheckDup["Проверка на дубликаты / совпадающие даты"] --> n1["Новый шаблон?"]
    Decision -- Да --> TemplateSel
    Validate --> CheckDup
    n1 -- Да --> UpdateRegistry
    n1 -- Нет --> ImportDB
    StoreAnalytics -- Записать --> Decision
    Analyst --> Visualize

    n1@{ shape: diam}
Loading

7caee3ad6977e3682a01328d35714906a635591b

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •