Skip to content
/ sms Public

Safety Management System - проект системы управления безопасностью на рейсах авиакомпаний. Laravel + Vue.js.

Notifications You must be signed in to change notification settings

Nikita-C47/sms

Repository files navigation

Safety Management System (SMS)

Проект по реализации системы управления безопасностью для авиакомпаний (SMS). Данная система является частью комплекса по обеспечению безопасности полетов. Обычно SMS включает в себя следующие компоненты:

  • Система регистрации событий на рейсах. База данных, в которой регистрируются события на рейсах авиакомпаний. Собирает события от самых простых (закончился кофе для пассажиров) до самых сложных (отказ системы);
  • Блок статистики. Отображает детальную статистику по отказам в разрезе месяцев и категорий событий. Представляет эти данные в удобных видах (например графически);
  • Блок анализа общей безопасности полетов в АК. Обычно представляет собой информацию о текущей обстановке с безопасностью полетов в АК. У каждого события есть тип, у типов есть факторы влияния на безопасность (к примеру у катастрофической ситуации фактор влияния больше, чем у усложнений условий полета). На основе общего количества событий того или иного типа и факторов этих типов и делается вывод об общей безопасности полетов в авиакомпании.

В данном проекте реализуется первый из этих трех компонентов. Это система, в которой регистрируются события на рейсах. Реализовать остальные компоненты в дополнение к ней не составит особого труда. Более подробную информацию о SMS, ее разработке и внедрении, вы можете найти здесь.

От автора

Данный проект является тестовым, но, в принципе, готов для использования на авиапредприятиях. Дело в том, что когда-то, когда я только начинал заниматься веб-разработкой, мы реализовали такую систему в авиакомпании, в которой я работал, но сделали это без фреймворков, на чистом PHP, JS и AJAX. Много лет спустя, я решил переписать этот проект на Laravel Framework, в качестве портфолио и платформы для собственного развития.

Обзор системы

Система состоит из нескольких компонентов, которые будут описаны ниже:

Авторизация

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

Система ролей

В системе существует три роли пользователей:

  • Пользователь. Может добавлять события. Идея в том, что обычные, рядовые пользователи отдела занимаются первичной регистрацией событий. В списке событий видит только события, которые были созданы им;
  • Менеджер событий. Имеет доступ к редактированию событий. В списке событий видят все события на предприятии. После создания события, получают уведомление об этом и обрабатывают события. Назначают ответственные подразделения, менеджеры событий которых в последствии и занимаются событием. Могут удалять события, но физически они останутся в базе данных (подробнее об этом ниже);
  • Администраторы. Имеют полный доступ к приложению. Могут править справочники, добавлять и удалять пользователей. Могут окончательно удалить событие из системы (подробнее об этом ниже).

Основная идея, чтобы сотрудники внутри отдела тесно работали над созданием и обработкой событий.

Анонимные события

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

Связь событий с рейсами

При создании события (не анонимно) можно поставить связь события с рейсом. В приложении есть таблица рейсов авиакомпании. Загрузку рейсов туда можно осуществлять через REST API (подробнее об этом в секции развертывания приложения). После загрузки, при создании события когда выбирается дата, будет отправлен фоновый запрос к таблице с поиском рейсов на указанную дату. После связи с рейсом, информация о нем будет подгружаться при просмотре события. Кроме этого, у событий связанных с рейсом, появляется возможность фильтрации по параметрам рейса (бортовой номер ВС, КВС).

Фильтры списка событий

Событий может быть много (в нашей системе накопилось 22928). Поэтому в приложении есть возможность фильтровать список событий. Фильтры доступны по следующим параметрам:

  • Начальная и конечная дата события;
  • Номер борта у связанного рейса;
  • КВС связанного рейса;
  • Где произошло событие;
  • Статус события;
  • Ответственные за событие подразделения;
  • Пользователь, создавший событие;
  • К чему относится событие;
  • Наличие / отсутствие прикрепленных файлов.

Фильтры, которые отображаются как чекбоксы (например номера бортов), работают по следующему принципу:

  • Если отмечены все галочки, фильтрация по данному свойству не производится;
  • Если отмечены некоторые галочки, будут показаны только события у которых в связанном рейсе есть борта из отмеченных;
  • Если не отмечено ни одной галочки, то фильтрация будет по принципу пустого значения. То есть в данном случае будут показаны все события, у которых нет номеров борта в связанном рейсе.

Иногда встречается частный случай. Например нужно показать все события, у которых в связанных рейсах есть бортовой номер. В этом случае нужно отметить все галочки, кроме "Все". Тогда все существующие значения бортов, будут записаны в фильтр.

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

Кроме фильтров, существует поиск события по его номеру.

Удаление событий

В системе реализован способ "мягкого удаления" событий. То есть при удалении, само событие физически остается в базе данных, просто пропадает из списка событий и при попытке его запросить будет выдан статус 404. Удалить событие из базы данных окончательно может только администратор системы. При удалении события удаляются все мероприятия по нему, ответственные подразделения и прикрепленные файлы. Если событие было удалено ошибочно, администратор системы может его восстановить.

Логирование

Для контроля за действиями пользователей, пишется лог их действий. По-умолчанию лог пишется по пути storage/logs/user_actions.log. Лог имеет ежедневный формат (то есть на каждый день создается свой файл). Приложение хранит логи за 14 дней (это, как и название сохраняемого файла, можно изменить). Логируются следующие события:

  • Авторизация пользователя;
  • Неудачная попытка авторизации;
  • Выход пользователя из приложения;
  • Сброс пароля пользователем;
  • Добавление события;
  • Добавление анонимного события;
  • Одобрение / отклонение анонимного события;
  • Редактирование события;
  • Удаление события;
  • Восстановление события;
  • Уничтожение события;
  • Загрузка рейса / рейсов через API;
  • Редактирование рейса через API;
  • Удаление рейса через API;
  • Добавление / изменение пользователя;
  • Сброс пароля пользователя через панель администрирования;
  • Авторизация под другим пользователем.

API

Для загрузки рейсов в систему присутствует API. API реализовано по стандартному подходу Laravel (подробнее - тут). API предоставляет полный спектр операций с рейсами. Их можно добавлять/редактировать/запрашивать/удалять.

Общее описание полей объекта "Рейс":

  • id - ID рейса в БД;
  • departure_datetime - дата и время вылета (форматы будут приведены ниже);
  • arrival_datetime - дата и время прилета;
  • number - номер рейса;
  • board - бортовой номер ВС;
  • aircraft_code - код ВС;
  • departure_airport - аэропорт вылета;
  • arrival_airport - аэропорт прилета;
  • captain - КВС;
  • extra_captain - второй КВС;
  • created_at - дата создания рейса в БД;
  • updated_at - дата обновления рейса в БД.

Для работы с API, необходимо указать три HTTP-заголовка:

  • Accept: application/json;
  • Content-Type: application/json;
  • Authorization: Bearer <токен доступа>.

Про токен доступа будет разъяснено ниже.

Загрузка рейсов

Для загрузки рейсов есть два метода. В обоих методах используется объект рейса. В первом методе можно загрузить один рейс, во втором - массив рейсов. Для массовой загрузки рейсов рекомендуется использовать второй метод.

Загрузка одного рейса
Тип URL
POST api/flights

Пример JSON для отправки:

{	
	"departure_datetime": "2020-03-02 02:00:00",
	"arrival_datetime": "2020-03-02 04:00:00",
	"number": "ARLN 16",
	"board": "VP-BJX",
	"aircraft_code": "735",
	"departure_airport": "Москва (Жуковский)",
	"arrival_airport": "Сочи (Адлер)",
	"captain": "Евгеньев Евгений Евгеньевич",
	"extra_captain": "Иванов Иван Иванович"
}
Загрузка нескольких рейсов
Тип URL
POST api/flights/load

Пример JSON для отправки:

{
	"flights": [
		{
			"departure_datetime": "2020-02-02 17:40:00",
			"arrival_datetime": "2020-02-02 19:20:00",
			"number": "ARLN 17",
			"board": "VQ-BFZ",
			"aircraft_code": "738",
			"departure_airport": "Калининград",
			"arrival_airport": "Москва (Домодедово)",
			"captain": "Иванов Иван Иванович"
		},
		{
			"departure_datetime": "2020-02-02 05:00:00",
			"arrival_datetime": "2020-02-02 07:00:00",
			"number": "ARLN 18",
			"board": "VQ-BPG",
			"aircraft_code": "738",
			"departure_airport": "Москва (Домодедово)",
			"arrival_airport": "Мурманск",
			"captain": "Иванов Иван Иванович"
		},
		{
			"departure_datetime": "2020-02-02 23:45:00",
			"arrival_datetime": "2020-02-03 10:30:00",
			"number": "ARLN 19",
			"board": "VQ-BLA",
			"aircraft_code": "772",
			"departure_airport": "Пунта-Кана",
			"arrival_airport": "Москва (Домодедово)",
			"captain": "Иванов Иван Иванович",
			"extra_captain": "Петров Петр Петрович"
		}
	]	
}

В ответ вернется объект с количеством добавленных рейсов (по сути должен совпасть с количеством переданных).

Получение полного списка рейсов в БД

Тип URL
GET api/flights

Список рейсов содержит список объектов типа "Рейс", описанного выше. Также важно учитывать, что для экономии ресурсов, список отображается в постраничном виде. На странице выводится по 15 записей.

Пример возвращаемого JSON (для удобства список рейсов сокращен до 3):

{
    "data": [
        {
            "id": 1,
            "departure_datetime": "2020-01-22T05:00:00.000000Z",
            "arrival_datetime": "2020-01-22T07:00:00.000000Z",
            "number": "ARLN 1",
            "board": "VP-BNU",
            "aircraft_code": "738",
            "departure_airport": "Москва (Домодедово)",
            "arrival_airport": "Оренбург (Центральный)",
            "captain": "Петров Петр Петрович",
            "extra_captain": "Иванов Иван Иванович",
            "created_at": "2020-02-05T14:33:28.000000Z",
            "updated_at": "2020-02-05T14:33:28.000000Z"
        },
        {
            "id": 2,
            "departure_datetime": "2020-01-22T06:00:00.000000Z",
            "arrival_datetime": "2020-01-22T07:30:00.000000Z",
            "number": "ARLN 2",
            "board": "VP-BNU",
            "aircraft_code": "738",
            "departure_airport": "Оренбург (Центральный)",
            "arrival_airport": "Москва (Домодедово)",
            "captain": "Петров Петр Петрович",
            "extra_captain": null,
            "created_at": "2020-02-05T14:33:28.000000Z",
            "updated_at": "2020-02-05T14:33:28.000000Z"
        },
        {
            "id": 3,
            "departure_datetime": "2020-01-22T07:00:00.000000Z",
            "arrival_datetime": "2020-01-22T08:00:00.000000Z",
            "number": "ARLN 3",
            "board": "VP-BVV",
            "aircraft_code": "772",
            "departure_airport": "Москва (Шереметьево)",
            "arrival_airport": "Оренбург (Центральный)",
            "captain": "Петров Петр Петрович",
            "extra_captain": "Сидоров Сидр Сидорович",
            "created_at": "2020-02-05T14:33:28.000000Z",
            "updated_at": "2020-02-05T14:33:28.000000Z"
        }        
    ],
    "links": {
        "first": "http://<адрес приложения>/api/flights?page=1",
        "last": "http://<адрес приложения>/api/flights?page=43",
        "prev": null,
        "next": "http://<адрес приложения>/api/flights?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 43,
        "path": "http://<адрес приложения>/api/flights",
        "per_page": 15,
        "to": 15,
        "total": 645
    }
}

Получение информации о рейсе по ID в БД

Тип URL
GET api/flights/<id рейсв>

Пример возвращаемого JSON:

{
    "data": {
        "id": 1,
        "departure_datetime": "2020-01-22 10:00:00",
        "arrival_datetime": "2020-01-22 12:00:00",
        "number": "ARLN 1",
        "board": "VP-BNU",
        "aircraft_code": "738",
        "departure_airport": "Москва (Домодедово)",
        "arrival_airport": "Оренбург (Центральный)",
        "captain": "Петров Петр Петрович",
        "extra_captain": "Иванов Иван Иванович",
        "created_at": "2020-02-05 19:33:28",
        "updated_at": "2020-02-05 19:33:28"
    }
}

Редактирование рейса по его ID в БД

Тип URL
PUT api/flights/<id рейсв>

Редактировать рейс можно частично. Если нужно изменить, к примеру, только дату вылета, можно указать только её, не обязательно снова полностью передавать информацию о рейсе. Если нужно обновить весь рейс, то JSON будет аналогичен созданию рейса.

Пример JSON для отправки:

{
  "extra_captain": "Евгеньев Евгений Евгеньевич"
}

В ответ вернется JSON с измененным объектом типа "Рейс".

Удаление рейса по его ID

Тип URL
DELETE api/flights/<id рейсв>

В ответ вернется сообщение об успешном удалении рейса.

Развертывание приложения

Теперь немного о технической части приложения. Система реализована на Laravel Framework. У этого фреймворка есть определенные требования к окружению.

Для подготовки среды развертывания, нужно выполнить следующие шаги:

  • Установить рекомендуемое ПО для запуска Laravel (там же можно найти рекомендации по настройке веб-сервера для отображения "красивых" адресов);
  • Установить СУБД. Laravel поддерживает несколько СУБД (полный список - тут), можно выбрать любую;
  • Установить движок очередей. Многие функции приложения выполняются отложенно (отправка писем или сообщений в лог) с помощью движка очередей. Laravel поддерживает множество движков очередей (в моем проекте использовался Redis). Полная информация о поддерживаемых движках - тут;
  • Настроить отправку почты. Уведомления в приложении отправляются через email, поэтому необходим почтовый сервер для отправки писем;
  • Установить git и Composer.

Развертывание проекта

Для развертывания проекта нужно выполнить следующие шаги:

  • Клонировать проект из git-репозитория (либо загрузить его) - git clone https://github.com/Nikita-C47/sms.git;
  • Перейти в корневую директорию проекта;
  • Установить зависимости (фреймворк и вспомогательные библиотеки) с помощью Composer - composer install;
  • Заполнить файл конфигурации приложения .env (если при установке он не создался автоматически, можно сохранить файл .env.example под этим именем). В нем необходимо заполнить следующие переменные (подробнее о заполнении файлов такого типа написано здесь):
    • APP_NAME - название приложения. Отоброжается, например, в заголовке вкладок со страницами приложенияж
    • APP_ENV - окружение приложения. При развертывание на рабочем сервере, нужно указать production. В завимости от окружения, в приложении варьируются некоторые параметры (об этом ниже);
    • APP_DEBUG - включение или отключение отладки. При включенной отладке все ошибки отображаются в браузере. На рабочем сервере должна быть отключена;
    • APP_URL - хост, на котором разворачивается приложение (используется, например, при генерации ссылок);
    • DB_CONNECTION - используемое подключение к СУБД (список поддерживаемых СУБД можно найти выше), там же описано как заполнять данный параметр и все параметры, связанные с БД;
    • DB_HOST - хост СУБД;
    • DB_PORT - порт СУБД;
    • DB_DATABASE - база данных приложения;
    • DB_USERNAME - имя пользователя для подключения к СУБД (пользователь должен иметь полные права на базу данных);
    • DB_PASSWORD - пароль пользователя для подключения к СУБД;
    • QUEUE_CONNECTION - используемый движок очередей. О поддерживаемых движках и заполнении этого параметра также можно прочитать выше. Обращаю внимание, что при использовании Redis, нужно будет заполнить секцию с его настройками. В частности переменные REDIS_HOST, REDIS_PASSWORD и REDIS_PORT;
    • MAIL_DRIVER - используемый драйвер для почты. Поддерживается как обычный SMTP, так и сторонние сервисы;
    • MAIL_HOST - хост сервера отправки электронной почты;
    • MAIL_PORT - порт сервера отправки электронной почты;
    • MAIL_USERNAME - имя пользователя для сервера отправки электронной почты;
    • MAIL_PASSWORD - пароль пользователя для сервера отправки электронной почты;
    • MAIL_ENCRYPTION - используемое шифрование электронной почты;
    • MAIL_FROM_ADDRESS - адрес, от которого ведется отправка сообщений;
    • MAIL_FROM_NAME - имя, от которого ведется отправка.
  • Сгенерировать ключ шифрования приложения - php artisan key:generate;
  • Добавить ссылку на публичное хранилище файлов (необходимо для возможности скачивать файлы, прикрепленные к событиям) - php artisan storage:link;
  • Запустить миграцию схемы БД приложения: php artisan migrate;
  • Запустить воркер для очередей (подробнее о том как это сделать - здесь. Там же можно найти конфигурацию для Supervisor, например);
  • Сгенерировать администратора для приложения. Он необходим для первичного входа и настройки приложения. Сделать это можно с помощью команды php artisan admin:assign <email пользователя>. Желательно указать реальный email пользователя. Администратор необходим чтобы получить доступ к функциям администрирования приложения, в том числе заполнению справочников и созданию пользователей;
  • Заполнить данные для справочников приложения. Это могут сделать администраторы, войдя в приложение. Необходимо заполнить типы событий, категории событий, мероприятия, к которым относятся события и подразделения компании (если нужны тестовые данные - смотрите ниже).

Дополнительная конфигурация

Есть несколько дополнительных шагов для конфигурирования приложения. Они обеспечивают его более тонкую настройку:

  • Заполнение приложения тестовыми данными (необходимо только при разработке и на тестовых серверах). В приложении есть три seeder-а (расположены в папке database/seeds):
    • DictionariesSeeder.php - заполняет приложение данными справочников. Указаны стандартные типы событий, категории событий, подразделения и мероприятия, к которым относятся события. Срабатывает на всех окружениях;
    • FlightsSeeder.php - заполняет рейсы. Берет дату на две недели раньше текущей и заполняет каждый день рейсами из определенного списка. Срабатывает только на не-production окружениях;
    • UsersSeeder.php - заполняет пользователей. Данный seeder должен запускаться после заполнения справочников, так как использует таблицу с подразделениями. Для каждого подразделения генерируется 10 пользователей - 4 обычных пользователя, 4 менеджера событий и 2 администратора. На не-production средах у всех пользователей устанавливаются пароли qwerty123, для простоты тестирования. Срабатывает только на не-production окружениях.
  • Настройка дополнительных параметров. Файлы конфигурации Laravel расположены в папке config. Среди наиболее важных настроек можно выделить:
    • Временная зона приложения. Файл app.php, параметр - timezone. Необходимо указать значение, поддерживаемое php. Список значений - тут;
    • Логин пользователя для API. Если вы хотите изменить логин пользователя, который будет иметь доступ к API приложения, это можно сделать в файле auth.php с помощью параметра api_user;
    • Путь к файлу для записи пользовательских действий. Конфигурируется в файле logging.php. В нем вы найдете массив channels, где есть элемент user_actions. В параметре path можно указать путь, по которому будет сохраняться лог пользовательских действий, а в параметре days - количество дней, за которые хранятся записи лога.
  • Генерация пользователя для API. Если вы планируете использовать API для загрузки рейсов в систему, необходимо сгенерировать пользователя для API. Это можно сделать с помощью команды php artisan api:generate. Будет создан пользователь для API и токен доступа для клиентского приложения будет в ответе на выполнение команды. Если Вы по какой-то причине его не записали - не беда, при повторном выполнении команды, будет сгенерирован и возвращен новый токен.

Лицензии

Сам Laravel распространяется по лицензии MIT, как и многие компоненты, входящие в этот проект (например Vue.js). Также огромная благодарность создателям шаблона для панели администрирования AdminCAST, на котором реализован интерфейс приложения. На использование проекта не налагается никаких ограничений, Вы можете модифицировать и изменять его по своему усмотрению. Моей целью в нем было только саморазвитие и еще один проект в портфолио. По всем вопросам, связанным с проектом, обращайтесь на мой контактный email - nikita_c47@outlook.com.

About

Safety Management System - проект системы управления безопасностью на рейсах авиакомпаний. Laravel + Vue.js.

Resources

Stars

Watchers

Forks

Packages

No packages published