diff --git a/.vscode/settings.json b/.vscode/settings.json
index f9a655bba44eda315c1d58f6d1dda68e25069ec8..d3abb169e8483de9d90cc454edb48266e06af854 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -129,7 +129,23 @@
         "qgridlayout": "cpp",
         "qboxlayout": "cpp",
         "qtextstream": "cpp",
-        "qcolordialog": "cpp"
+        "qcolordialog": "cpp",
+        "qstringlist": "cpp",
+        "qserialport": "cpp",
+        "qsharedpointer": "cpp",
+        "qcombobox": "cpp",
+        "*.def": "cpp",
+        "csetjmp": "cpp",
+        "csignal": "cpp",
+        "any": "cpp",
+        "hash_set": "cpp",
+        "strstream": "cpp",
+        "slist": "cpp",
+        "future": "cpp",
+        "scoped_allocator": "cpp",
+        "shared_mutex": "cpp",
+        "span": "cpp",
+        "qlistwidget": "cpp"
     },
     "editor.defaultFormatter": "ms-vscode.cpptools",
     "[xml]": {
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 10e3c7db2d54686da6e1129b4ab412e28f3bf73c..82372af8417c126345c9ff31415d064163488196 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -46,18 +46,16 @@ add_executable(groundstation
     src/shared/Components/ToggleButton/ToggleButton.cpp
     src/shared/Components/ErrorDisplayer/Error.cpp
     src/shared/Components/ErrorDisplayer/ErrorDisplayer.cpp
-    src/shared/Components/TopicAndFieldFilterSelector/TopicAndFieldFilterSelector.cpp
-    src/shared/Components/TopicFilterSelector/TopicFilterSelector.cpp
-    src/shared/Core/Message/MessageField.cpp
-    src/shared/Core/Message/ModuleMessage.cpp
+    src/shared/Components/FilterSelector/FilterSelector.cpp
+    src/shared/Core/EventHandler/EventHandler.cpp
+    src/shared/Core/Message/Field.cpp
+    src/shared/Core/Message/Filter.cpp
+    src/shared/Core/Message/Message.cpp
     src/shared/Core/Message/Topic.cpp
-    src/shared/Core/Message/TopicAndFieldFilter.cpp
-    src/shared/Core/Message/TopicFilter.cpp
+    src/shared/Core/MessageBroker/MessageBroker.cpp
+    src/shared/Core/Module/Module.cpp
+    src/shared/Core/ModulesManager/ModulesManager.cpp
     src/shared/Core/QCustomPlot/QCustomPlot.cpp
-    src/shared/Core/Module.cpp
-    src/shared/Core/ModuleEventsHandler.cpp
-    src/shared/Core/ModuleMessagesBroker.cpp
-    src/shared/Core/ModulesManager.cpp
     src/shared/Core/SkywardHubCore.cpp
     src/shared/Core/XmlObject.cpp
     src/shared/Modules/CommandPad/CommandPad.cpp
diff --git a/SkywardHub.pro b/SkywardHub.pro
index 55b1d3efc2a279f21631f21ac245a2d913b20689..c5f3472aabce1eb94f5af97510dfac0dbd3c196f 100644
--- a/SkywardHub.pro
+++ b/SkywardHub.pro
@@ -14,141 +14,141 @@ ICON = src/entrypoints/groundstation/assets/icons/SkywardHub.icns
 # Windows app icon
 RC_ICONS = src/entrypoints/groundstation/assets/icons/SkywardHub.ico
 
-INCLUDEPATH += src/shared \
+INCLUDEPATH += \
+    src/shared \
     libs/mavlink-skyward-lib
 
 SOURCES += \
-    src/shared/Components/ContextMenuSeparator/contextmenuseparator.cpp \
-    src/shared/Components/ModulesPicker/modulespicker.cpp \
-    src/shared/Components/SaveConfigurationDialog/saveconfigurationdialog.cpp \
-    src/shared/Components/SubscriptionsPanel/subscriptionspanel.cpp \
-    src/shared/Components/ToggleButton/togglebutton.cpp \
-    src/shared/Components/ErrorDisplayer/error.cpp \
-    src/shared/Components/ErrorDisplayer/errordisplayer.cpp \
-    src/shared/Components/TopicAndFieldFilterSelector/topicandfieldfilterselector.cpp \
-    src/shared/Components/TopicFilterSelector/topicfilterselector.cpp \
-    src/shared/Core/Message/messagefield.cpp \
-    src/shared/Core/Message/modulemessage.cpp \
-    src/shared/Core/Message/topic.cpp \
-    src/shared/Core/Message/topicandfieldfilter.cpp \
-    src/shared/Core/Message/topicfilter.cpp \
-    src/shared/Core/QCustomPlot/QCustomPlot.cpp \
-    src/shared/Core/module.cpp \
-    src/shared/Core/moduleeventshandler.cpp \
-    src/shared/Core/modulemessagesbroker.cpp \
-    src/shared/Core/modulesmanager.cpp \
-    src/shared/Core/skywardhubcore.cpp \
-    src/shared/Core/xmlobject.cpp \
+    src/shared/Modules/Empty/EmptyModule.cpp \
+    src/shared/Modules/ValuesConverterViewer/ValuesViewerConfigPanel.cpp \
+    src/shared/Modules/ValuesConverterViewer/ValueElement.cpp \
+    src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.cpp \
+    src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.cpp \
+    src/shared/Modules/TimerController/TimerControllerModule.cpp \
+    src/shared/Modules/OrientationVisualizer/OrientationVisualizer.cpp \
+    src/shared/Modules/SkywardHub/PrefabViewElement.cpp \
+    src/shared/Modules/SkywardHub/PrefabDialog.cpp \
+    src/shared/Modules/SkywardHub/DeployerPathPicker.cpp \
+    src/shared/Modules/SkywardHub/Deployer.cpp \
+    src/shared/Modules/SkywardHub/SkywardHubModule.cpp \
+    src/shared/Modules/StateViewer/StateViewer.cpp \
+    src/shared/Modules/FileStream/FileStreamModule.cpp \
+    src/shared/Modules/Graph/Graph.cpp \
+    src/shared/Modules/Test/TestModule.cpp \
+    src/shared/Modules/ModulesList.cpp \
+    src/shared/Modules/Splitter/Splitter.cpp \
+    src/shared/Modules/DefaultModule/DefaultModule.cpp \
     src/shared/Modules/CommandPad/CommandPad.cpp \
     src/shared/Modules/CommandPad/MessageFormElement.cpp \
+    src/shared/Modules/MainWindow/SkywardHubMainWindow.cpp \
+    src/shared/Modules/MainWindow/Window.cpp \
+    src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.cpp \
     src/shared/Modules/CompactCommandPad/CompactCommandPad.cpp \
+    src/shared/Modules/CompactCommandPad/SendThread.cpp \
     src/shared/Modules/CompactCommandPad/CommandSelector.cpp \
-    src/shared/Modules/DefaultModule/defaultmodule.cpp \
-    src/shared/Modules/Empty/emptymodule.cpp \
-    src/shared/Modules/FileStream/filestreammodule.cpp \
-    src/shared/Modules/Graph/Graph.cpp \
-    src/shared/Modules/IncomingMessagesViewer/incomingmessagesviewermodule.cpp \
-    src/shared/Modules/MainWindow/skywardhubmainwindow.cpp \
-    src/shared/Modules/MainWindow/window.cpp \
-    src/shared/Modules/Mavlink/mavlinkcommandadapter.cpp \
-    src/shared/Modules/Mavlink/mavlinkmodule.cpp \
-    src/shared/Modules/Mavlink/mavlinkreader.cpp \
-    src/shared/Modules/Mavlink/mavlinkrocketmsgtestingmodule.cpp \
-    src/shared/Modules/Mavlink/mavlinkwriter.cpp \
-    src/shared/Modules/OutgoingMessagesViewer/outgoingmessagesviewermodule.cpp \
-    src/shared/Modules/SkywardHub/deployer.cpp \
-    src/shared/Modules/SkywardHub/deployerpathpicker.cpp \
-    src/shared/Modules/SkywardHub/prefabdialog.cpp \
-    src/shared/Modules/SkywardHub/prefabviewelement.cpp \
-    src/shared/Modules/SkywardHub/skywardhubmodule.cpp \
-    src/shared/Modules/Splitter/Splitter.cpp \
-    src/shared/Modules/StateViewer/StateViewer.cpp \
-    src/shared/Modules/Tabs/tabsmodule.cpp \
-    src/shared/Modules/Test/testmodule.cpp \
-    src/shared/Modules/TimerController/timercontrollermodule.cpp \
-    src/shared/Modules/ValuesConverterViewer/valueelement.cpp \
-    src/shared/Modules/ValuesConverterViewer/valuesconverterviewermodule.cpp \
-    src/shared/Modules/ValuesConverterViewer/valuesviewerconfigpanel.cpp \
-    src/shared/Modules/moduleinfo.cpp \
-    src/shared/Modules/moduleslist.cpp \
+    src/shared/Modules/Tabs/TabsModule.cpp \
+    src/shared/Modules/ModuleInfo.cpp \
+    src/shared/Modules/Mavlink/MavlinkWriter.cpp \
+    src/shared/Modules/Mavlink/MavlinkReader.cpp \
+    src/shared/Modules/Mavlink/MavlinkCommandAdapter.cpp \
+    src/shared/Modules/Mavlink/MavlinkModule.cpp \
+    src/shared/Modules/Mavlink/MavlinkRocketMsgTestingModule.cpp \
+    src/shared/Core/EventHandler/EventHandler.cpp \
+    src/shared/Core/XmlObject.cpp \
+    src/shared/Core/QCustomPlot/QCustomPlot.cpp \
+    src/shared/Core/MessageBroker/MessageBroker.cpp \
+    src/shared/Core/Module/Module.cpp \
+    src/shared/Core/SkywardHubCore.cpp \
+    src/shared/Core/Message/Filter.cpp \
+    src/shared/Core/Message/Field.cpp \
+    src/shared/Core/Message/Topic.cpp \
+    src/shared/Core/Message/Message.cpp \
+    src/shared/Core/ModulesManager/ModulesManager.cpp \
+    src/shared/Components/ContextMenuSeparator/ContextMenuSeparator.cpp \
+    src/shared/Components/FilterSelector/FilterSelector.cpp \
+    src/shared/Components/ModulesPicker/ModulesPicker.cpp \
+    src/shared/Components/SaveConfigurationDialog/SaveConfigurationDialog.cpp \
+    src/shared/Components/ErrorDisplayer/Error.cpp \
+    src/shared/Components/ErrorDisplayer/ErrorDisplayer.cpp \
+    src/shared/Components/ToggleButton/ToggleButton.cpp \
+    src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp \
     src/entrypoints/groundstation/main.cpp
 
 HEADERS += \
-    src/shared/Components/ContextMenuSeparator/contextmenuseparator.h \
-    src/shared/Components/ModulesPicker/modulespicker.h \
-    src/shared/Components/SaveConfigurationDialog/saveconfigurationdialog.h \
-    src/shared/Components/SubscriptionsPanel/subscriptionspanel.h \
-    src/shared/Components/ToggleButton/togglebutton.h \
-    src/shared/Components/ErrorDisplayer/error.h \
-    src/shared/Components/ErrorDisplayer/errordisplayer.h \
-    src/shared/Components/TopicAndFieldFilterSelector/topicandfieldfilterselector.h \
-    src/shared/Components/TopicFilterSelector/topicfilterselector.h \
-    src/shared/Core/Message/messagefield.h \
-    src/shared/Core/Message/modulemessage.h \
-    src/shared/Core/Message/topic.h \
-    src/shared/Core/Message/topicandfieldfilter.h \
-    src/shared/Core/Message/topicfilter.h \
-    src/shared/Core/QCustomPlot/QCustomPlot.h \
-    src/shared/Core/module.h \
-    src/shared/Core/moduleeventshandler.h \
-    src/shared/Core/modulemessagesbroker.h \
-    src/shared/Core/modulesmanager.h \
-    src/shared/Core/skywardhubcore.h \
-    src/shared/Core/xmlobject.h \
-    src/shared/Modules/CommandPad/CommandPad.h \
+    src/shared/Modules/Empty/EmptyModule.h \
+    src/shared/Modules/ValuesConverterViewer/ValueElement.h \
+    src/shared/Modules/ValuesConverterViewer/ValuesViewerConfigPanel.h \
+    src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.h \
+    src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.h \
+    src/shared/Modules/TimerController/TimerControllerModule.h \
+    src/shared/Modules/ModuleInfo.h \
+    src/shared/Modules/OrientationVisualizer/OrientationVisualizer.h \
+    src/shared/Modules/SkywardHub/SkywardHubModule.h \
+    src/shared/Modules/SkywardHub/PrefabDialog.h \
+    src/shared/Modules/SkywardHub/Deployer.h \
+    src/shared/Modules/SkywardHub/DeployerPathPicker.h \
+    src/shared/Modules/SkywardHub/PrefabViewElement.h \
+    src/shared/Modules/StateViewer/StatesList.h \
+    src/shared/Modules/StateViewer/StateViewer.h \
+    src/shared/Modules/FileStream/FileStreamModule.h \
+    src/shared/Modules/Graph/Graph.h \
+    src/shared/Modules/Test/TestModule.h \
+    src/shared/Modules/SkywardHubStrings.h \
+    src/shared/Modules/Splitter/Splitter.h \
+    src/shared/Modules/DefaultModule/DefaultModule.h \
     src/shared/Modules/CommandPad/MessageFormElement.h \
+    src/shared/Modules/CommandPad/CommandPad.h \
     src/shared/Modules/CommandPad/MessagesList.h \
+    src/shared/Modules/MainWindow/SkywardHubMainWindow.h \
+    src/shared/Modules/MainWindow/Window.h \
+    src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.h \
     src/shared/Modules/CompactCommandPad/CompactCommandPad.h \
     src/shared/Modules/CompactCommandPad/CommandSelector.h \
-    src/shared/Modules/DefaultModule/defaultmodule.h \
-    src/shared/Modules/Empty/emptymodule.h \
-    src/shared/Modules/FileStream/filestreammodule.h \
-    src/shared/Modules/Graph/Graph.h \
-    src/shared/Modules/IncomingMessagesViewer/incomingmessagesviewermodule.h \
-    src/shared/Modules/MainWindow/skywardhubmainwindow.h \
-    src/shared/Modules/MainWindow/window.h \
-    src/shared/Modules/Mavlink/mavlinkcommandadapter.h \
-    src/shared/Modules/Mavlink/mavlinkmodule.h \
-    src/shared/Modules/Mavlink/mavlinkreader.h \
-    src/shared/Modules/Mavlink/mavlinkrocketmsgtestingmodule.h \
-    src/shared/Modules/Mavlink/mavlinkversionheader.h \
-    src/shared/Modules/Mavlink/mavlinkversionheader.h \
-    src/shared/Modules/Mavlink/mavlinkwriter.h \
-    src/shared/Modules/OutgoingMessagesViewer/outgoingmessagesviewermodule.h \
-    src/shared/Modules/SkywardHub/deployer.h \
-    src/shared/Modules/SkywardHub/deployerpathpicker.h \
-    src/shared/Modules/SkywardHub/prefabdialog.h \
-    src/shared/Modules/SkywardHub/prefabviewelement.h \
-    src/shared/Modules/SkywardHub/skywardhubmodule.h \
-    src/shared/Modules/Splitter/Splitter.h \
-    src/shared/Modules/StateViewer/StateViewer.h \
-    src/shared/Modules/Tabs/tabsmodule.h \
-    src/shared/Modules/Test/testmodule.h \
-    src/shared/Modules/TimerController/timercontrollermodule.h \
-    src/shared/Modules/ValuesConverterViewer/valueelement.h \
-    src/shared/Modules/ValuesConverterViewer/valuesconverterviewermodule.h \
-    src/shared/Modules/ValuesConverterViewer/valuesviewerconfigpanel.h \
-    src/shared/Modules/moduleinfo.h \
-    src/shared/Modules/moduleslist.h \
-    src/shared/Modules/skywardhubstrings.h
+    src/shared/Modules/CompactCommandPad/SendThread.h \
+    src/shared/Modules/Tabs/TabsModule.h \
+    src/shared/Modules/Mavlink/MavlinkReader.h \
+    src/shared/Modules/Mavlink/MavlinkRocketMsgTestingModule.h \
+    src/shared/Modules/Mavlink/MavlinkWriter.h \
+    src/shared/Modules/Mavlink/MavlinkVersionHeader.h \
+    src/shared/Modules/Mavlink/MavlinkModule.h \
+    src/shared/Modules/Mavlink/MavlinkCommandAdapter.h \
+    src/shared/Modules/ModulesList.h \
+    src/shared/Core/EventHandler/EventHandler.h \
+    src/shared/Core/QCustomPlot/QCustomPlot.h \
+    src/shared/Core/MessageBroker/MessageBroker.h \
+    src/shared/Core/SkywardHubCore.h \
+    src/shared/Core/Module/Module.h \
+    src/shared/Core/XmlObject.h \
+    src/shared/Core/Message/Message.h \
+    src/shared/Core/Message/Filter.h \
+    src/shared/Core/Message/Field.h \
+    src/shared/Core/Message/Topic.h \
+    src/shared/Core/ModulesManager/ModulesManager.h \
+    src/shared/Components/ContextMenuSeparator/ContextMenuSeparator.h \
+    src/shared/Components/FilterSelector/FilterSelector.h \
+    src/shared/Components/ModulesPicker/ModulesPicker.h \
+    src/shared/Components/SaveConfigurationDialog/SaveConfigurationDialog.h \
+    src/shared/Components/ErrorDisplayer/ErrorDisplayer.h \
+    src/shared/Components/ErrorDisplayer/Error.h \
+    src/shared/Components/ToggleButton/ToggleButton.h \
+    src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.h \
 
 FORMS += \
-    src/shared/Components/ModulesPicker/modulespicker.ui \
-    src/shared/Components/SaveConfigurationDialog/saveconfigurationdialog.ui \
-    src/shared/Components/SubscriptionsPanel/subscriptionspanel.ui \
-    src/shared/Modules/Empty/emptymodule.ui \
-    src/shared/Modules/FileStream/filestreammodule.ui \
-    src/shared/Modules/MainWindow/window.ui \
-    src/shared/Modules/Mavlink/mavlinkrocketmsgtestingmodule.ui \
-    src/shared/Modules/OutgoingMessagesViewer/outgoingmessagesviewermodule.ui \
-    src/shared/Modules/SkywardHub/deployerpathpicker.ui \
-    src/shared/Modules/SkywardHub/prefabdialog.ui \
-    src/shared/Modules/SkywardHub/prefabviewelement.ui \
-    src/shared/Modules/SkywardHub/skywardhubmodule.ui \
-    src/shared/Modules/Test/testmodule.ui \
-    src/shared/Modules/TimerController/timercontrollermodule.ui \
-    src/shared/Modules/ValuesConverterViewer/valuesconverterviewermodule.ui \
-    src/shared/Modules/ValuesConverterViewer/valuesviewerconfigpanel.ui
+    src/shared/Modules/Empty/EmptyModule.ui \
+    src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.ui \
+    src/shared/Modules/ValuesConverterViewer/ValuesViewerConfigPanel.ui \
+    src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.ui \
+    src/shared/Modules/TimerController/TimerControllerModule.ui \
+    src/shared/Modules/SkywardHub/SkywardHubModule.ui \
+    src/shared/Modules/SkywardHub/PrefabViewElement.ui \
+    src/shared/Modules/SkywardHub/PrefabDialog.ui \
+    src/shared/Modules/SkywardHub/DeployerPathPicker.ui \
+    src/shared/Modules/FileStream/FileStreamModule.ui \
+    src/shared/Modules/Test/TestModule.ui \
+    src/shared/Modules/MainWindow/Window.ui \
+    src/shared/Modules/Mavlink/MavlinkRocketMsgTestingModule.ui \
+    src/shared/Components/ModulesPicker/ModulesPicker.ui \
+    src/shared/Components/SaveConfigurationDialog/SaveConfigurationDialog.ui \
 
 # Default rules for deployment.
 qnx: target.path = /tmp/$${TARGET}/bin
diff --git a/src/shared/Components/ErrorDisplayer/Error.h b/src/shared/Components/ErrorDisplayer/Error.h
index 085c88d712eba0f9bf1309382060e9470b59d509..9e91cbd9e921fd7040cb2b1309c50ce010cd78e2 100644
--- a/src/shared/Components/ErrorDisplayer/Error.h
+++ b/src/shared/Components/ErrorDisplayer/Error.h
@@ -1,5 +1,9 @@
 #pragma once
 
+#include <Core/Message/Message.h>
+#include <Core/MessageBroker/MessageBroker.h>
+#include <Core/SkywardHubCore.h>
+
 #include <QGridLayout>
 #include <QLabel>
 #include <QString>
@@ -8,10 +12,6 @@
 #include <QWidget>
 #include <QtWidgets>
 
-#include "Core/Message/ModuleMessage.h"
-#include "Core/ModuleMessagesBroker.h"
-#include "Core/SkywardHubCore.h"
-
 enum ErrorType
 {
     ET_ERROR,
diff --git a/src/shared/Components/FilterSelector/FilterSelector.cpp b/src/shared/Components/FilterSelector/FilterSelector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6439081dcbd496352af3043dfb416f62df97db6c
--- /dev/null
+++ b/src/shared/Components/FilterSelector/FilterSelector.cpp
@@ -0,0 +1,124 @@
+#include "FilterSelector.h"
+
+#include <Modules/Mavlink/MavlinkVersionHeader.h>
+
+#include <QLabel>
+#include <QPushButton>
+
+void FilterSelector::setupUi()
+{
+    setAttribute(Qt::WA_DeleteOnClose, true);
+    setWindowTitle("Build Filter");
+
+    QVBoxLayout *layout = new QVBoxLayout;
+
+    QHBoxLayout *topicLayout = new QHBoxLayout;
+
+    QLabel *mainTopic = new QLabel;
+    mainTopic->setText("Mav");
+    topicLayout->addWidget(mainTopic);
+
+    QLabel *topicSeparator = new QLabel;
+    topicSeparator->setText("/");
+    topicLayout->addWidget(topicSeparator);
+
+    QComboBox *subTopic = new QComboBox;
+    subTopic->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+    subTopic->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+    subTopic->addItems(messages.keys());
+    topicLayout->addWidget(subTopic, 1);
+
+    layout->addLayout(topicLayout);
+
+    fieldsLayout = new QVBoxLayout;
+    layout->addLayout(fieldsLayout);
+
+    QHBoxLayout *buttons = new QHBoxLayout;
+    QPushButton *cancel  = new QPushButton("Cancel");
+    buttons->addWidget(cancel);
+    QPushButton *select = new QPushButton("Select");
+    buttons->addWidget(select);
+    layout->addLayout(buttons);
+
+    // Set default message
+    currentMessage = messages.keys().at(0);
+    subTopic->setCurrentText(currentMessage);
+    fieldsLayout->addWidget(fields[currentMessage]);
+
+    connect(subTopic, &QComboBox::currentTextChanged, this,
+            [=](QString key)
+            {
+                if (messages.contains(key))
+                {
+                    fieldsLayout->removeWidget(fields[currentMessage]);
+                    fieldsLayout->addWidget(fields[key]);
+                    currentMessage = key;
+                }
+            });
+    connect(cancel, &QPushButton::clicked, [this]() { deleteLater(); });
+    connect(select, &QPushButton::clicked,
+            [=]()
+            {
+                Filter filter(Topic("Mav/" + subTopic->currentText()));
+                filter.addField(fields[currentMessage]->currentText());
+
+                emit filterSelected(filter);
+                deleteLater();
+            });
+
+    setLayout(layout);
+}
+
+void FilterSelector::selectFilter(FilterSelector::Handler handler)
+{
+    FilterSelector *selector = new FilterSelector();
+    QObject::connect(selector, &FilterSelector::filterSelected, handler);
+    selector->show();
+}
+
+void FilterSelector::selectFilter(const Filter &filter,
+                                  FilterSelector::Handler handler)
+{
+    FilterSelector *selector = new FilterSelector(filter);
+    QObject::connect(selector, &FilterSelector::filterSelected, handler);
+    selector->show();
+}
+
+FilterSelector::FilterSelector()
+{
+    parseMessagesList();
+    setupUi();
+}
+
+FilterSelector::FilterSelector(const Filter &filter) : filter(filter)
+{
+    parseMessagesList();
+    setupUi();
+}
+
+void FilterSelector::parseMessagesList()
+{
+    mavlink_message_info_t messagesList[256] = MAVLINK_MESSAGE_INFO;
+
+    for (unsigned int i = 0; i < 255; i++)
+    {
+        // Check if the message is empty
+        if (strcmp(messagesList[i].name, "EMPTY") != 0)
+        {
+            QList<QString> fields;
+
+            for (unsigned int ii = 0; ii < messagesList[i].num_fields; ii++)
+                fields.append(messagesList[i].fields[ii].name);
+
+            messages[messagesList[i].name] = fields;
+        }
+    }
+
+    // Prepare fields combo boxes
+    for (auto messageName : messages.keys())
+    {
+        auto comboBox = new QComboBox();
+        comboBox->addItems(messages[messageName]);
+        fields[messageName] = comboBox;
+    }
+}
diff --git a/src/shared/Components/FilterSelector/FilterSelector.h b/src/shared/Components/FilterSelector/FilterSelector.h
new file mode 100644
index 0000000000000000000000000000000000000000..f1586d4c930ea85d6168dd1d5f1452b81066e58e
--- /dev/null
+++ b/src/shared/Components/FilterSelector/FilterSelector.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <Core/Message/Filter.h>
+
+#include <QBoxLayout>
+#include <QComboBox>
+#include <QList>
+#include <QMap>
+#include <QString>
+
+class FilterSelector : public QWidget
+{
+    Q_OBJECT
+
+public:
+    using Handler = std::function<void(const Filter& filter)>;
+
+    static void selectFilter(Handler handler);
+    static void selectFilter(const Filter& filter, Handler handler);
+
+private:
+    FilterSelector();
+    explicit FilterSelector(const Filter& filter);
+
+    void parseMessagesList();
+    void setupUi();
+
+    Filter filter;
+
+    QString currentMessage;
+    QVBoxLayout* fieldsLayout;
+
+    QMap<QString, QList<QString>> messages;
+    QMap<QString, QComboBox*> fields;
+
+signals:
+    void filterSelected(const Filter&);
+};
diff --git a/src/shared/Components/ModulesPicker/ModulesPicker.cpp b/src/shared/Components/ModulesPicker/ModulesPicker.cpp
index 61c1fc93b8da0c41641df272f2f18396f710f71a..ffe2528e273c7868b6c39dc40335204d3caaf5be 100644
--- a/src/shared/Components/ModulesPicker/ModulesPicker.cpp
+++ b/src/shared/Components/ModulesPicker/ModulesPicker.cpp
@@ -1,11 +1,11 @@
 #include "ModulesPicker.h"
 
+#include <Core/ModulesManager/ModulesManager.h>
 #include <Modules/Splitter/Splitter.h>
 
 #include <QDebug>
 #include <QPushButton>
 
-#include "Core/ModulesManager.h"
 #include "ui_ModulesPicker.h"
 
 ModulesPicker::ModulesPicker() : QDialog(), ui(new Ui::ModulesPicker)
@@ -13,9 +13,9 @@ ModulesPicker::ModulesPicker() : QDialog(), ui(new Ui::ModulesPicker)
     ui->setupUi(this);
     createAndConnectUI();
 
-    this->setAttribute(Qt::WA_DeleteOnClose,
-                       true);  // WA_DeleteOnClose is set to true, so this
-                               // widget will be deleted on close
+    setAttribute(Qt::WA_DeleteOnClose,
+                 true);  // WA_DeleteOnClose is set to true, so this
+                         // widget will be deleted on close
 }
 
 ModulesPicker::~ModulesPicker() { delete ui; }
diff --git a/src/shared/Components/ModulesPicker/ModulesPicker.h b/src/shared/Components/ModulesPicker/ModulesPicker.h
index ad65edfd53add5f3dbd0494acd839c32dd27dde9..e89ac269a8d58f6a3349d67e57c65744ee1d1e47 100644
--- a/src/shared/Components/ModulesPicker/ModulesPicker.h
+++ b/src/shared/Components/ModulesPicker/ModulesPicker.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <Core/Module.h>
+#include <Core/Module/Module.h>
 
 #include <QDialog>
 #include <QPushButton>
diff --git a/src/shared/Components/SaveConfigurationDialog/SaveConfigurationDialog.cpp b/src/shared/Components/SaveConfigurationDialog/SaveConfigurationDialog.cpp
index 8c51e3c6aa45cc5c3adf4e1ad4640b9aa0da646b..84c7ee4dc282ac8320f7a61a5833f67eea6811dc 100644
--- a/src/shared/Components/SaveConfigurationDialog/SaveConfigurationDialog.cpp
+++ b/src/shared/Components/SaveConfigurationDialog/SaveConfigurationDialog.cpp
@@ -8,9 +8,9 @@ SaveConfigurationDialog::SaveConfigurationDialog(QWidget *parent)
     : QDialog(parent), ui(new Ui::SaveConfigurationDialog)
 {
     ui->setupUi(this);
-    this->setAttribute(Qt::WA_DeleteOnClose,
-                       true);  // WA_DeleteOnClose is set to true, so this
-                               // widget will be deleted on close
+    setAttribute(Qt::WA_DeleteOnClose,
+                 true);  // WA_DeleteOnClose is set to true, so this
+                         // widget will be deleted on close
 
     connect(ui->pushButton_saveConfig, &QPushButton::clicked, this,
             &SaveConfigurationDialog::onSaveConfigClicked);
diff --git a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp
index 42ca6d6c79abec1460003e8e22148e719d75e871..90def45996b75f8618169f18dd4ad58dc83a3edb 100644
--- a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp
+++ b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.cpp
@@ -1,73 +1,81 @@
 #include "SubscriptionsPanel.h"
 
+#include <Components/FilterSelector/FilterSelector.h>
+
+#include <QBoxLayout>
 #include <QDebug>
+#include <QListWidget>
+#include <QPushButton>
 #include <functional>
 
-#include "Components/TopicFilterSelector/TopicFilterSelector.h"
-#include "ui_SubscriptionsPanel.h"
-
 using namespace std;
 
-SubscriptionsPanel::SubscriptionsPanel(
-    const QList<TopicAndFieldFilter>& filters)
-    : QWidget(nullptr), ui(new Ui::SubscriptionsPanel)
+SubscriptionsPanel::SubscriptionsPanel()
+{
+    setAttribute(Qt::WA_DeleteOnClose, true);
+    setWindowTitle("Subscriptions panel");
+    setupUi();
+}
+
+SubscriptionsPanel::SubscriptionsPanel(const QList<Filter>& filters)
+    : QWidget(nullptr)
 {
-    ui->setupUi(this);
-    this->setAttribute(Qt::WA_DeleteOnClose, true);
+    setAttribute(Qt::WA_DeleteOnClose, true);
+    resize({500, 200});
+
+    setWindowTitle("Subscriptions panel");
+    setupUi();
 
     for (auto filter : filters)
-        addTopicAndFieldFilter(filter);
-
-    connect(ui->button_addTopic, &QPushButton::clicked, this,
-            &SubscriptionsPanel::onAddTopicClicked);
-    connect(ui->button_addTopicAndField, &QPushButton::clicked, this,
-            &SubscriptionsPanel::onAddTopicAndFieldClicked);
-    connect(ui->button_remove, &QPushButton::clicked, this,
-            &SubscriptionsPanel::onRemoveClicked);
+        addFilter(filter);
 }
 
-SubscriptionsPanel::~SubscriptionsPanel() { delete ui; }
-
-void SubscriptionsPanel::addTopicAndFieldFilter(
-    const TopicAndFieldFilter& filter)
+void SubscriptionsPanel::addFilter(const Filter& filter)
 {
-    QListWidgetItem* listItem = new QListWidgetItem(filter.toString());
-    ui->subscriptions_list->addItem(listItem);
+    filtersList->addItem(new QListWidgetItem(filter.toString()));
     emit topicAndFieldFilterAdded(filter);
 }
 
-void SubscriptionsPanel::addTopicFilter(const TopicFilter& filter)
+void SubscriptionsPanel::setupUi()
 {
-    QListWidgetItem* listItem = new QListWidgetItem(filter.toString());
-    ui->subscriptions_list->addItem(listItem);
-    auto filter2 = TopicAndFieldFilter(filter);
-    emit topicAndFieldFilterAdded(filter2);
-}
+    QVBoxLayout* layout = new QVBoxLayout;
 
-void SubscriptionsPanel::removeSubscription(QListWidgetItem* item)
-{
-    emit topicAndFieldFilterRemoved(
-        TopicAndFieldFilter::fromStringUnsafe(item->text()));
-    delete item;
-}
+    filtersList = new QListWidget;
+    layout->addWidget(filtersList);
 
-void SubscriptionsPanel::onAddTopicClicked()
-{
-    TopicFilterSelector::selectFilter([&](const TopicFilter& filter)
-                                      { addTopicFilter(filter); });
-}
+    QHBoxLayout* buttonsLayout = new QHBoxLayout;
 
-void SubscriptionsPanel::onAddTopicAndFieldClicked()
-{
-    // TODO: Fix
-    // TopicFilterSelector::selectFilter([&](const TopicAndFieldFilter& filter)
-    //                                   { addTopicAndFieldFilter(filter); });
+    QPushButton* addButton = new QPushButton;
+    addButton->setText("Add filter");
+    buttonsLayout->addWidget(addButton);
+    QPushButton* removeButton = new QPushButton;
+    removeButton->setText("Remove filter");
+    buttonsLayout->addWidget(removeButton);
+
+    layout->addLayout(buttonsLayout);
+
+    setLayout(layout);
+
+    connect(addButton, &QPushButton::clicked, this,
+            [&]()
+            {
+                FilterSelector::selectFilter(
+                    [&](const Filter& filter)
+                    {
+                        qDebug() << "New filter:" << filter.toString();
+                        addFilter(filter);
+                    });
+            });
+    connect(removeButton, &QPushButton::clicked, this,
+            [&]()
+            {
+                for (auto item : filtersList->selectedItems())
+                    removeSubscription(item);
+            });
 }
 
-void SubscriptionsPanel::onRemoveClicked()
+void SubscriptionsPanel::removeSubscription(QListWidgetItem* item)
 {
-    auto items = ui->subscriptions_list->selectedItems();
-
-    for (auto item : items)
-        removeSubscription(item);
+    emit topicAndFieldFilterRemoved(Filter::fromString(item->text()));
+    delete item;
 }
diff --git a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.h b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.h
index cc0407294cd11b3aa02c1db9167c17f94e0f3911..1fdff87822a011688d54ff2506c4072671d8b584 100644
--- a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.h
+++ b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.h
@@ -1,37 +1,28 @@
 #pragma once
 
+#include <Core/Message/Filter.h>
+
 #include <QList>
 #include <QListWidgetItem>
 #include <QWidget>
 
-#include "Core/Message/TopicAndFieldFilter.h"
-
-namespace Ui
-{
-class SubscriptionsPanel;
-}
-
 class SubscriptionsPanel : public QWidget
 {
     Q_OBJECT
 
 public:
-    explicit SubscriptionsPanel(const QList<TopicAndFieldFilter>& filters);
-    ~SubscriptionsPanel();
+    SubscriptionsPanel();
+    explicit SubscriptionsPanel(const QList<Filter>& filters);
 
-    void addTopicAndFieldFilter(const TopicAndFieldFilter& filter);
-    void addTopicFilter(const TopicFilter& filter);
-    void removeSubscription(QListWidgetItem* item);
-
-private slots:
-    void onAddTopicClicked();
-    void onAddTopicAndFieldClicked();
-    void onRemoveClicked();
+    void addFilter(const Filter& filter);
 
 signals:
-    void topicAndFieldFilterAdded(const TopicAndFieldFilter&);
-    void topicAndFieldFilterRemoved(const TopicAndFieldFilter&);
+    void topicAndFieldFilterAdded(const Filter&);
+    void topicAndFieldFilterRemoved(const Filter&);
 
 private:
-    Ui::SubscriptionsPanel* ui;
+    void setupUi();
+    void removeSubscription(QListWidgetItem* item);
+
+    QListWidget* filtersList;
 };
diff --git a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.ui b/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.ui
deleted file mode 100644
index 4db0fd77b27c18343d381ca78b1428a821b9c41e..0000000000000000000000000000000000000000
--- a/src/shared/Components/SubscriptionsPanel/SubscriptionsPanel.ui
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SubscriptionsPanel</class>
- <widget class="QWidget" name="SubscriptionsPanel">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>651</width>
-    <height>316</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Form</string>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <widget class="QListWidget" name="subscriptions_list">
-     <property name="dragEnabled">
-      <bool>false</bool>
-     </property>
-     <property name="sortingEnabled">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <item>
-      <widget class="QPushButton" name="button_addTopic">
-       <property name="text">
-        <string>Add Topic</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QPushButton" name="button_addTopicAndField">
-       <property name="text">
-        <string>Add Topic and Field</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QPushButton" name="button_remove">
-       <property name="text">
-        <string>Remove</string>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/shared/Components/TopicAndFieldFilterSelector/TopicAndFieldFilterSelector.cpp b/src/shared/Components/TopicAndFieldFilterSelector/TopicAndFieldFilterSelector.cpp
deleted file mode 100644
index 880074ea0591a46f2a1df3e2419236ecc44e89dc..0000000000000000000000000000000000000000
--- a/src/shared/Components/TopicAndFieldFilterSelector/TopicAndFieldFilterSelector.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-
-#include "TopicAndFieldFilterSelector.h"
-
-#include <QFormLayout>
-#include <QLineEdit>
-#include <QMessageBox>
-#include <QPushButton>
-
-TopicAndFieldFilterSelector::TopicAndFieldFilterSelector(
-    const TopicAndFieldFilter& filter)
-{
-    setAttribute(Qt::WA_DeleteOnClose, true);
-    setWindowTitle("Choose Topic and Field name");
-
-    QFormLayout* form = new QFormLayout;
-    form->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
-    QLineEdit* topicEdit = new QLineEdit;
-    topicEdit->setText(filter.getTopicFilter().toString());
-    form->addRow("Topic:", topicEdit);
-    QLineEdit* fieldEdit = new QLineEdit;
-    fieldEdit->setText(filter.getFieldFilter());
-    form->addRow("Field:", fieldEdit);
-
-    QHBoxLayout* buttons = new QHBoxLayout;
-    QPushButton* cancel  = new QPushButton("Cancel");
-    buttons->addWidget(cancel);
-    QPushButton* select = new QPushButton("Select");
-    buttons->addWidget(select);
-
-    QVBoxLayout* outer = new QVBoxLayout;
-    outer->addLayout(form);
-    outer->addLayout(buttons);
-    setLayout(outer);
-
-    auto onSelect = [=]()
-    {
-        if (topicEdit->text().isEmpty() || fieldEdit->text().isEmpty())
-        {
-            QMessageBox msgBox(nullptr);
-            msgBox.setText("Cannot accept empty fields");
-            msgBox.exec();
-        }
-        else
-        {
-            TopicAndFieldFilter newFilter(topicEdit->text(), fieldEdit->text());
-
-            emit filterSelected(newFilter);
-            deleteLater();
-        }
-    };
-
-    connect(cancel, &QPushButton::clicked, [this]() { deleteLater(); });
-    connect(select, &QPushButton::clicked, onSelect);
-    connect(topicEdit, &QLineEdit::returnPressed, onSelect);
-}
-
-void TopicAndFieldFilterSelector::selectFilter(
-    TopicAndFieldFilterSelector::Handler handler)
-{
-    TopicAndFieldFilterSelector* selector = new TopicAndFieldFilterSelector({});
-    QObject::connect(selector, &TopicAndFieldFilterSelector::filterSelected,
-                     handler);
-    selector->show();
-}
-
-void TopicAndFieldFilterSelector::selectFilter(
-    const TopicAndFieldFilter& filter, Handler handler)
-{
-    TopicAndFieldFilterSelector* selector =
-        new TopicAndFieldFilterSelector(filter);
-    QObject::connect(selector, &TopicAndFieldFilterSelector::filterSelected,
-                     handler);
-    selector->show();
-}
diff --git a/src/shared/Components/TopicAndFieldFilterSelector/TopicAndFieldFilterSelector.h b/src/shared/Components/TopicAndFieldFilterSelector/TopicAndFieldFilterSelector.h
deleted file mode 100644
index 5e1c0e7301a77392d8c299db2a1b1ade6c67736c..0000000000000000000000000000000000000000
--- a/src/shared/Components/TopicAndFieldFilterSelector/TopicAndFieldFilterSelector.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-#include <QPair>
-#include <QString>
-#include <QWidget>
-#include <functional>
-
-#include "Core/Message/TopicAndFieldFilter.h"
-
-class TopicAndFieldFilterSelector : public QWidget
-{
-    Q_OBJECT
-
-public:
-    using Handler = std::function<void(const TopicAndFieldFilter& filter)>;
-
-    static void selectFilter(Handler handler);
-    static void selectFilter(const TopicAndFieldFilter& filter,
-                             Handler handler);
-
-private:
-    explicit TopicAndFieldFilterSelector(const TopicAndFieldFilter& filter);
-
-signals:
-    void filterSelected(const TopicAndFieldFilter&);
-};
diff --git a/src/shared/Components/TopicFilterSelector/TopicFilterSelector.cpp b/src/shared/Components/TopicFilterSelector/TopicFilterSelector.cpp
deleted file mode 100644
index 643a7b6a7c928b173966b622e9bbf0d1f032b676..0000000000000000000000000000000000000000
--- a/src/shared/Components/TopicFilterSelector/TopicFilterSelector.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#include "TopicFilterSelector.h"
-
-#include <QFormLayout>
-#include <QLineEdit>
-#include <QMessageBox>
-#include <QPushButton>
-
-TopicFilterSelector::TopicFilterSelector(const TopicFilter& filter)
-{
-    setAttribute(Qt::WA_DeleteOnClose, true);
-    setWindowTitle("Choose Topic and Field name");
-
-    QFormLayout* form = new QFormLayout;
-    form->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
-    QLineEdit* topicEdit = new QLineEdit;
-    topicEdit->setText(filter.toString());
-    form->addRow("Topic:", topicEdit);
-
-    QHBoxLayout* buttons = new QHBoxLayout;
-    QPushButton* cancel  = new QPushButton("Cancel");
-    buttons->addWidget(cancel);
-    QPushButton* select = new QPushButton("Select");
-    buttons->addWidget(select);
-
-    QVBoxLayout* outer = new QVBoxLayout;
-    outer->addLayout(form);
-    outer->addLayout(buttons);
-    setLayout(outer);
-
-    auto onSelect = [=]()
-    {
-        if (topicEdit->text().isEmpty())
-        {
-            QMessageBox msgBox(nullptr);
-            msgBox.setText("Cannot accept empty fields");
-            msgBox.exec();
-        }
-        else
-        {
-            TopicFilter newFilter(topicEdit->text());
-
-            emit filterSelected(newFilter);
-            deleteLater();
-        }
-    };
-
-    connect(cancel, &QPushButton::clicked, [this]() { deleteLater(); });
-    connect(select, &QPushButton::clicked, onSelect);
-    connect(topicEdit, &QLineEdit::returnPressed, onSelect);
-}
-
-void TopicFilterSelector::selectFilter(TopicFilterSelector::Handler handler)
-{
-    TopicFilterSelector* selector = new TopicFilterSelector({});
-    QObject::connect(selector, &TopicFilterSelector::filterSelected, handler);
-    selector->show();
-}
-
-void TopicFilterSelector::selectFilter(const TopicFilter& filter,
-                                       Handler handler)
-{
-    TopicFilterSelector* selector = new TopicFilterSelector(filter);
-    QObject::connect(selector, &TopicFilterSelector::filterSelected, handler);
-    selector->show();
-}
diff --git a/src/shared/Components/TopicFilterSelector/TopicFilterSelector.h b/src/shared/Components/TopicFilterSelector/TopicFilterSelector.h
deleted file mode 100644
index 158eb722d14b918614f47c965769ec88eb92d463..0000000000000000000000000000000000000000
--- a/src/shared/Components/TopicFilterSelector/TopicFilterSelector.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma once
-
-#include <QPair>
-#include <QString>
-#include <QWidget>
-#include <functional>
-
-#include "Core/Message/TopicFilter.h"
-
-class TopicFilterSelector : public QWidget
-{
-    Q_OBJECT
-
-public:
-    using Handler = std::function<void(const TopicFilter& filter)>;
-
-    static void selectFilter(Handler handler);
-    static void selectFilter(const TopicFilter& filter, Handler handler);
-
-private:
-    explicit TopicFilterSelector(const TopicFilter& filter);
-
-signals:
-    void filterSelected(const TopicFilter&);
-};
diff --git a/src/shared/Core/EventHandler/EventHandler.cpp b/src/shared/Core/EventHandler/EventHandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5ce62e57dfbdab9f023a9dc62c23466281f5e8c6
--- /dev/null
+++ b/src/shared/Core/EventHandler/EventHandler.cpp
@@ -0,0 +1,3 @@
+#include "EventHandler.h"
+
+EventHandler::EventHandler() {}
\ No newline at end of file
diff --git a/src/shared/Core/ModuleEventsHandler.h b/src/shared/Core/EventHandler/EventHandler.h
similarity index 81%
rename from src/shared/Core/ModuleEventsHandler.h
rename to src/shared/Core/EventHandler/EventHandler.h
index ea2242625a4c714724e9bb23b5d22d77f1db1c37..f04e22d283d5a2692226e5c859bb59e9fc1a40b7 100644
--- a/src/shared/Core/ModuleEventsHandler.h
+++ b/src/shared/Core/EventHandler/EventHandler.h
@@ -4,12 +4,13 @@
 #include <QObject>
 
 class Module;
-class ModuleEventsHandler : public QObject
+
+class EventHandler : public QObject
 {
     Q_OBJECT
 
 public:
-    ModuleEventsHandler();
+    EventHandler();
 
 signals:
     void beforeDelete(Module *module);
diff --git a/src/shared/Core/Message/Field.cpp b/src/shared/Core/Message/Field.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..23f42935d26e1bf8bb5938b42165d1bef459f50a
--- /dev/null
+++ b/src/shared/Core/Message/Field.cpp
@@ -0,0 +1,96 @@
+#include "Field.h"
+
+#include <QRegExp>
+
+Field::Field() : type(Type::EMPTY) {}
+
+Field::Field(int64_t value) : type(Type::INT), signedInteger(value) {}
+
+Field::Field(uint64_t value) : type(Type::UINT), unsignedInteger(value) {}
+
+Field::Field(double value) : type(Type::DOUBLE), floatingPoint(value) {}
+
+Field::Field(QString value) : type(Type::STRING), string(value) {}
+
+bool Field::operator==(const Field& toCompare) const
+{
+    if (type != toCompare.type)
+        return false;
+
+    switch (type)
+    {
+        case Type::INT:
+            return signedInteger == toCompare.signedInteger;
+        case Type::UINT:
+            return unsignedInteger == toCompare.unsignedInteger;
+        case Type::DOUBLE:
+            return floatingPoint == toCompare.floatingPoint;
+        case Type::STRING:
+            return string == toCompare.string;
+        case Type::EMPTY:
+            return true;
+    }
+
+    return false;
+}
+
+Field::Type Field::getType() const { return type; }
+
+int64_t Field::getInteger() const
+{
+    if (type == Type::INT)
+        return signedInteger;
+    else
+        return 0;
+}
+
+uint64_t Field::getUnsignedInteger() const
+{
+    if (type == Type::UINT)
+        return unsignedInteger;
+    else
+        return 0;
+}
+
+double Field::getDouble() const
+{
+    if (type == Type::DOUBLE)
+        return floatingPoint;
+    else
+        return 0;
+}
+
+QString Field::getString() const
+{
+    if (type == Type::STRING)
+        return string;
+    else
+        return QString();
+}
+
+QString Field::toString() const
+{
+    switch (type)
+    {
+        case Type::INT:
+            return QString::number(signedInteger);
+        case Type::UINT:
+            return QString::number(unsignedInteger);
+        case Type::DOUBLE:
+        {
+            QString str = QString::number(floatingPoint, 'f', 8);
+
+            // Remove any number of trailing 0's
+            str.remove(QRegExp("0+$"));
+
+            // If the last character is just a '.' then remove it
+            str.remove(QRegExp("\\.$"));
+
+            return str;
+        }
+        case Type::STRING:
+            return string;
+        default:
+            return QString();
+    }
+};
\ No newline at end of file
diff --git a/src/shared/Core/Message/Field.h b/src/shared/Core/Message/Field.h
new file mode 100644
index 0000000000000000000000000000000000000000..50d0af6103534e40cf11204dadd9a65e430dfda6
--- /dev/null
+++ b/src/shared/Core/Message/Field.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <stdint.h>
+
+#include <QString>
+
+class Field
+{
+public:
+    enum class Type
+    {
+        INT,
+        UINT,
+        DOUBLE,
+        STRING,
+        EMPTY
+    };
+
+    Field();
+    explicit Field(int64_t value);
+    explicit Field(uint64_t value);
+    explicit Field(double value);
+    explicit Field(QString value);
+
+    bool operator==(const Field& toCompare) const;
+
+    Type getType() const;
+
+    /// @brief Returns value if the field is of type INT
+    int64_t getInteger() const;
+
+    /// @brief Returns value if the field is of type UINT
+    uint64_t getUnsignedInteger() const;
+
+    /// @brief Returns value if the field is of type DOUBLE
+    double getDouble() const;
+
+    /// @brief Returns value if the field is of type STRING
+    QString getString() const;
+
+    QString toString() const;
+
+private:
+    Type type;
+    QString string;
+
+    union
+    {
+        int64_t signedInteger;
+        uint64_t unsignedInteger;
+        double floatingPoint;
+    };
+};
\ No newline at end of file
diff --git a/src/shared/Core/Message/Filter.cpp b/src/shared/Core/Message/Filter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..85acceeedf25310474764ba2e8fd2a4adfd76d88
--- /dev/null
+++ b/src/shared/Core/Message/Filter.cpp
@@ -0,0 +1,88 @@
+#include "Filter.h"
+
+Filter::Filter() {}
+
+Filter::Filter(Topic topic) : topic(topic) {}
+
+Filter::Filter(Topic topic, QSet<QString> fields) : topic(topic), fields(fields)
+{
+}
+
+bool Filter::operator==(const Filter& toCompare) const
+{
+    return topic == toCompare.topic &&
+           ((fields.isEmpty() && toCompare.fields.isEmpty()) ||
+            (fields == toCompare.fields));
+}
+
+bool Filter::operator<(const Filter& toCompare) const
+{
+    return topic < toCompare.topic;
+}
+
+void Filter::setTopic(Topic topic) { this->topic = topic; }
+
+Topic Filter::getTopic() const { return topic; }
+
+void Filter::addField(QString field) { fields.insert(field); }
+
+bool Filter::removeField(QString field) { return fields.remove(field); }
+
+QSet<QString> Filter::getFields() const { return fields; }
+
+bool Filter::match(const Message& message) const
+{
+    return this->topic == message.getTopic();
+}
+
+bool Filter::filterMessage(Message& message) const
+{
+    // Check if the message matches the topic
+    if (!match(message))
+        return false;
+
+    // If the filter specifies at leas one field, filter them
+    if (fields.size() > 0)
+        message.filterFields(fields);
+
+    return true;
+}
+
+QString Filter::toString() const
+{
+    QString string;
+
+    string += topic.toString();
+    string += ":";
+
+    if (!fields.isEmpty())
+    {
+        auto list = fields.values();
+        for (int i = 0; i < list.size() - 1; i++)
+            string += list[i] + ",";
+        string += list.last();
+    }
+    else
+    {
+        string += "*";
+    }
+
+    return string;
+}
+
+Filter Filter::fromString(QString string)
+{
+    int idxCol = string.indexOf(':');
+
+    auto filter = Filter(Topic(string.left(idxCol)));
+
+    if (idxCol > 0)
+    {
+        auto right = string.right(string.size() - 1 - idxCol);
+
+        for (auto field : right.split(','))
+            filter.addField(field);
+    }
+
+    return filter;
+}
diff --git a/src/shared/Core/Message/Filter.h b/src/shared/Core/Message/Filter.h
new file mode 100644
index 0000000000000000000000000000000000000000..c086b769a239f34a69e438f885a5d9f762a4c79b
--- /dev/null
+++ b/src/shared/Core/Message/Filter.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <QSet>
+#include <QString>
+
+#include "Message.h"
+
+/**
+ * @brief A filter specifies a topic and an optional list of fields.
+ *
+ * The topic can contain wildcard symbols * and ? as last token. For example:
+ * - "*" and "?" match with all topics
+ * - "Prefix/?" matches with "Prefix", "Prefix/A" and "Prefix/A/B"
+ * - "Prefix/*" matches with "Prefix/A" and "Prefix/A/B"
+ *
+ * The difference between * and ? is that the latter also matches when only the
+ * prefix is present.
+ */
+class Filter
+{
+public:
+    Filter();
+    explicit Filter(Topic topic);
+    Filter(Topic topic, QSet<QString> fields);
+
+    bool operator==(const Filter& toCompare) const;
+    bool operator<(const Filter& toCompare) const;
+
+    void setTopic(Topic topic);
+    Topic getTopic() const;
+
+    void addField(QString field);
+    bool removeField(QString field);
+    QSet<QString> getFields() const;
+
+    /**
+     * @brief Checks if the message topic is matched by the filter.
+     */
+    bool match(const Message& message) const;
+
+    /**
+     * @brief Keeps only the fields specified by the filter.
+     *
+     * If the filter has no fields then the messages is not modified.
+     */
+    bool filterMessage(Message& message) const;
+
+    QString toString() const;
+    static Filter fromString(QString string);
+
+private:
+    Topic topic;
+    QSet<QString> fields;
+};
diff --git a/src/shared/Core/Message/Message.cpp b/src/shared/Core/Message/Message.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8da9c4efd3ab81a2308c615519064cd3784186f2
--- /dev/null
+++ b/src/shared/Core/Message/Message.cpp
@@ -0,0 +1,57 @@
+#include "Message.h"
+
+Message::Message() {}
+
+Message::Message(Topic topic) : topic(topic) {}
+
+void Message::setTopic(Topic topic) { this->topic = topic; }
+
+Topic Message::getTopic() const { return topic; }
+
+void Message::setField(QString key, const Field& field) { fields[key] = field; }
+
+Field Message::getField(QString key) const { return fields[key]; }
+
+bool Message::removeField(QString key) { return fields.remove(key); }
+
+void Message::setFields(const QMap<QString, Field>& fields)
+{
+    this->fields = fields;
+}
+
+QMap<QString, Field> Message::getFields() const { return fields; }
+
+void Message::filterFields(const QSet<QString>& fields)
+{
+    auto copy = this->fields;
+
+    this->fields = QMap<QString, Field>();
+
+    for (auto field : fields.values())
+    {
+        if (copy.contains(field))
+            this->fields[field] = copy[field];
+    }
+}
+
+QString Message::toString() const
+{
+    QString str;
+
+    if (fields.size() > 1)
+    {
+        str += "{\n";
+
+        for (auto key : fields.keys())
+            str += "    " + key + ": " + fields[key].toString() + "\n";
+
+        str.append("}");
+    }
+    else if (fields.size() == 1)
+    {
+        auto key = fields.keys().first();
+        str      = key + ": " + fields[key].toString();
+    }
+
+    return str;
+}
\ No newline at end of file
diff --git a/src/shared/Core/Message/Message.h b/src/shared/Core/Message/Message.h
new file mode 100644
index 0000000000000000000000000000000000000000..9898c8c63ffe5f74a5fb9eee98e7cb9f8189c0ac
--- /dev/null
+++ b/src/shared/Core/Message/Message.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <QMap>
+#include <QSet>
+
+#include "Field.h"
+#include "Topic.h"
+
+/**
+ * @brief Messages associates values to topics.
+ */
+class Message
+{
+public:
+    Message();
+    explicit Message(Topic topic);
+
+    void setTopic(Topic topic);
+    Topic getTopic() const;
+
+    void setField(QString key, const Field& field);
+    Field getField(QString key) const;
+    bool removeField(QString key);
+
+    void setFields(const QMap<QString, Field>& fields);
+    QMap<QString, Field> getFields() const;
+
+    void filterFields(const QSet<QString>& fields);
+
+    QString toString() const;
+
+private:
+    Topic topic;
+    QMap<QString, Field> fields;
+};
\ No newline at end of file
diff --git a/src/shared/Core/Message/MessageField.cpp b/src/shared/Core/Message/MessageField.cpp
deleted file mode 100644
index 4be8bb4e6828d613ebcfd0d3ee9c0f1c421251b2..0000000000000000000000000000000000000000
--- a/src/shared/Core/Message/MessageField.cpp
+++ /dev/null
@@ -1,324 +0,0 @@
-#include "MessageField.h"
-
-MessageField::MessageField() : type(Type::EMPTY) {}
-
-MessageField::MessageField(const MessageField& rhs) { operator=(rhs); }
-
-MessageField::MessageField(MessageField&& rhs) { operator=(rhs); }
-
-MessageField& MessageField::operator=(const MessageField& rhs)
-{
-    type = rhs.type;
-
-    switch (type)
-    {
-        case Type::INTEGER:
-            i64 = rhs.i64;
-            break;
-        case Type::UINTEGER:
-            u64 = rhs.u64;
-            break;
-        case Type::DOUBLE:
-            d = rhs.d;
-            break;
-        case Type::CHAR:
-            c = rhs.c;
-            break;
-        case Type::STRING:
-            s = rhs.s;
-            break;
-        case Type::ARRAY:
-        {
-            a = rhs.a;
-            break;
-        }
-        case Type::EMPTY:
-        default:
-            break;
-    }
-
-    return *this;
-}
-
-MessageField& MessageField::operator=(MessageField&& rhs)
-{
-    type = rhs.type;
-
-    switch (type)
-    {
-        case Type::INTEGER:
-            i64 = rhs.i64;
-            break;
-        case Type::UINTEGER:
-            u64 = rhs.u64;
-            break;
-        case Type::DOUBLE:
-            d = rhs.d;
-            break;
-        case Type::CHAR:
-            c = rhs.c;
-            break;
-        case Type::STRING:
-            s = std::move(rhs.s);
-            break;
-        case Type::ARRAY:
-        {
-            a = std::move(rhs.a);
-            break;
-        }
-        case Type::EMPTY:
-        default:
-            break;
-    }
-
-    return *this;
-}
-
-MessageField::MessageField(int64_t _i64) : type(Type::INTEGER), i64(_i64) {}
-MessageField::MessageField(uint64_t _u64) : type(Type::UINTEGER), u64(_u64) {}
-MessageField::MessageField(double _d) : type(Type::DOUBLE), d(_d) {}
-MessageField::MessageField(char _c) : type(Type::CHAR), c(_c) {}
-MessageField::MessageField(QString _s) : type(Type::STRING), s(_s) {}
-MessageField::MessageField(const QList<MessageField>& _a)
-    : type(Type::ARRAY), a(_a)
-{
-}
-MessageField::MessageField(QList<MessageField>&& _a) : type(Type::ARRAY), a(_a)
-{
-}
-
-int64_t MessageField::getInteger(int64_t defaultValue) const
-{
-    if (type == Type::INTEGER)
-    {
-        return i64;
-    }
-    else
-    {
-        return defaultValue;
-    }
-}
-
-uint64_t MessageField::getUInteger(uint64_t defaultValue) const
-{
-    if (type == Type::UINTEGER)
-    {
-        return u64;
-    }
-    else
-    {
-        return defaultValue;
-    }
-}
-
-double MessageField::getDouble(double defaultValue) const
-{
-    if (type == Type::DOUBLE)
-    {
-        return d;
-    }
-    else
-    {
-        return defaultValue;
-    }
-}
-
-char MessageField::getChar(char defaultValue) const
-{
-    if (type == Type::CHAR)
-    {
-        return c;
-    }
-    else
-    {
-        return defaultValue;
-    }
-}
-
-QString MessageField::getString() const
-{
-    switch (type)
-    {
-        case Type::INTEGER:
-            return QString::number(i64);
-        case Type::UINTEGER:
-            return QString::number(u64);
-        case Type::DOUBLE:
-            return QString::number(d);
-        case Type::CHAR:
-            return QString(c);
-        case Type::STRING:
-            return s;
-        case Type::ARRAY:
-        {
-            QString out = "[";
-            for (int i = 0; i < a.size(); i++)
-            {
-                out.append(a[i].getString());
-                if (i != a.size() - 1)
-                {
-                    out.append(", ");
-                }
-            }
-            out.append("]");
-            return out;
-        }
-        default:
-            return QString();
-    }
-}
-
-const QList<MessageField>& MessageField::getArray() const
-{
-    /* If type != ARRAY, a is empty */
-    return a;
-}
-
-void MessageField::set(int64_t value)
-{
-    if (type == Type::STRING)
-    {
-        s.clear();
-    }
-    else if (type == Type::ARRAY)
-    {
-        a.clear();
-    }
-
-    type = Type::INTEGER;
-    i64  = value;
-}
-
-void MessageField::set(uint64_t value)
-{
-    if (type == Type::STRING)
-    {
-        s.clear();
-    }
-    else if (type == Type::ARRAY)
-    {
-        a.clear();
-    }
-
-    type = Type::UINTEGER;
-    u64  = value;
-}
-
-void MessageField::set(double value)
-{
-    if (type == Type::STRING)
-    {
-        s.clear();
-    }
-    else if (type == Type::ARRAY)
-    {
-        a.clear();
-    }
-
-    type = Type::DOUBLE;
-    d    = value;
-}
-
-void MessageField::set(char value)
-{
-    if (type == Type::STRING)
-    {
-        s.clear();
-    }
-    else if (type == Type::ARRAY)
-    {
-        a.clear();
-    }
-
-    type = Type::CHAR;
-    c    = value;
-}
-
-void MessageField::set(QString value)
-{
-    if (type == Type::STRING)
-    {
-        s.clear();
-    }
-    else if (type == Type::ARRAY)
-    {
-        a.clear();
-    }
-
-    type = Type::STRING;
-    s    = value;
-}
-
-void MessageField::set(const QList<MessageField>& value)
-{
-    if (type == Type::STRING)
-    {
-        s.clear();
-    }
-    else if (type == Type::ARRAY)
-    {
-        a.clear();
-    }
-
-    type = Type::ARRAY;
-    a    = value;
-}
-
-void MessageField::set(QList<MessageField>&& value)
-{
-    if (type == Type::STRING)
-    {
-        s.clear();
-    }
-    else if (type == Type::ARRAY)
-    {
-        a.clear();
-    }
-
-    type = Type::ARRAY;
-    a    = value;
-}
-
-void MessageField::set()
-{
-    if (type == Type::STRING)
-    {
-        s.clear();
-    }
-    else if (type == Type::ARRAY)
-    {
-        a.clear();
-    }
-
-    type = Type::EMPTY;
-}
-
-bool MessageField::operator==(const MessageField& rhs) const
-{
-    if (type != rhs.type)
-    {
-        return false;
-    }
-
-    switch (type)
-    {
-        case Type::INTEGER:
-            return i64 == rhs.i64;
-        case Type::UINTEGER:
-            return u64 == rhs.u64;
-        case Type::DOUBLE:
-            return d == rhs.d;
-        case Type::CHAR:
-            return c == rhs.c;
-        case Type::STRING:
-            return s == rhs.s;
-        case Type::ARRAY:
-            return a == rhs.a;
-        case Type::EMPTY:
-            return true;
-    }
-
-    return false;
-}
-
-MessageField::Type MessageField::getType() const { return type; }
diff --git a/src/shared/Core/Message/MessageField.h b/src/shared/Core/Message/MessageField.h
deleted file mode 100644
index cf5497dc16cddf91e261df1db16242ebac04a59c..0000000000000000000000000000000000000000
--- a/src/shared/Core/Message/MessageField.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#pragma once
-
-#include <QList>
-#include <QString>
-#include <cstdint>
-
-class MessageField
-{
-public:
-    enum class Type
-    {
-        EMPTY,
-        INTEGER,
-        UINTEGER,
-        DOUBLE,
-        CHAR,
-        STRING,
-        ARRAY
-    };
-
-    MessageField();
-    MessageField(const MessageField& rhs);
-    MessageField(MessageField&& rhs);
-    MessageField& operator=(const MessageField& rhs);
-    MessageField& operator=(MessageField&& rhs);
-
-    explicit MessageField(int64_t _i64);
-    explicit MessageField(uint64_t _u64);
-    explicit MessageField(double _d);
-    explicit MessageField(char _c);
-    explicit MessageField(QString _s);
-    explicit MessageField(const QList<MessageField>& _a);
-    explicit MessageField(QList<MessageField>&& _a);
-
-    int64_t getInteger(int64_t defaultValue) const;
-    uint64_t getUInteger(uint64_t defaultValue) const;
-    double getDouble(double defaultValue) const;
-    char getChar(char defaultValue) const;
-    QString getString() const;
-    const QList<MessageField>& getArray() const;
-
-    void set(int64_t value);
-    void set(uint64_t value);
-    void set(double value);
-    void set(char value);
-    void set(QString value);
-    void set(const QList<MessageField>& value);
-    void set(QList<MessageField>&& value);
-    void set();
-
-    bool operator==(const MessageField& rhs) const;
-    Type getType() const;
-
-private:
-    Type type;
-    QString s;
-    QList<MessageField> a;
-
-    union
-    {
-        int64_t i64;
-        uint64_t u64;
-        double d;
-        char c;
-    };
-};
diff --git a/src/shared/Core/Message/ModuleMessage.cpp b/src/shared/Core/Message/ModuleMessage.cpp
deleted file mode 100644
index cbb1d9ebe75d3f18fe5635d5e1a86f58dc8f81f3..0000000000000000000000000000000000000000
--- a/src/shared/Core/Message/ModuleMessage.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#include "ModuleMessage.h"
-
-ModuleMessage::ModuleMessage() {}
-
-ModuleMessage::ModuleMessage(Topic _topic) : topic(_topic) {}
-
-ModuleMessage::ModuleMessage(const ModuleMessage& rhs)
-    : topic(rhs.topic), fields(rhs.fields)
-{
-}
-
-ModuleMessage::ModuleMessage(ModuleMessage&& rhs)
-    : topic(rhs.topic), fields(std::move(rhs.fields))
-{
-}
-
-ModuleMessage& ModuleMessage::operator=(const ModuleMessage& rhs)
-{
-    topic  = rhs.topic;
-    fields = rhs.fields;
-    return *this;
-}
-
-ModuleMessage& ModuleMessage::operator=(ModuleMessage&& rhs)
-{
-    topic  = rhs.topic;
-    fields = std::move(rhs.fields);
-    return *this;
-}
-
-MessageField ModuleMessage::getField(QString key) const
-{
-    auto it = fields.find(key);
-    if (it == fields.cend())
-    {
-        return {};
-    }
-
-    return *it;
-}
-
-Topic ModuleMessage::getTopic() const { return topic; }
-
-void ModuleMessage::setField(QString key, const MessageField& field)
-{
-    fields[key] = field;
-}
-
-void ModuleMessage::setTopic(Topic _topic) { topic = _topic; }
-
-void ModuleMessage::setFields(const QMap<QString, MessageField>& _fields)
-{
-    fields = _fields;
-}
-
-void ModuleMessage::setFields(QMap<QString, MessageField>&& _fields)
-{
-    fields = std::move(_fields);
-}
-
-void ModuleMessage::filterFields(const QString& fieldFilter)
-{
-    for (auto it = fields.begin(); it != fields.end(); it++)
-        if (it.key() != fieldFilter)
-            fields.remove(it.key());
-}
-
-QString ModuleMessage::toString(bool includeTopic) const
-{
-    QString str = "{\n\t";
-    if (includeTopic)
-    {
-        str.append("<topic>: ");
-        str.append(topic.toString());
-    }
-
-    for (auto it = fields.keyBegin(); it != fields.keyEnd(); ++it)
-    {
-        if (includeTopic || it != fields.keyBegin())
-        {
-            str.append(",\n\t");
-        }
-        str.append(*it);
-        str.append(": ");
-        str.append(fields[*it].getString());
-    }
-    str.append("\n}");
-    return str;
-}
diff --git a/src/shared/Core/Message/ModuleMessage.h b/src/shared/Core/Message/ModuleMessage.h
deleted file mode 100644
index 19209574391b2cd0f98ea2be8c1183e4a8ef3aef..0000000000000000000000000000000000000000
--- a/src/shared/Core/Message/ModuleMessage.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#pragma once
-
-#include <QMap>
-#include <QTime>
-
-#include "MessageField.h"
-#include "Topic.h"
-
-/*
- * Structure of internal GS Messages.
- *
- */
-class ModuleMessage
-{
-public:
-    ModuleMessage();
-    explicit ModuleMessage(Topic topic);
-
-    ModuleMessage(const ModuleMessage& rhs);
-    ModuleMessage(ModuleMessage&& rhs);
-    ModuleMessage& operator=(const ModuleMessage& rhs);
-    ModuleMessage& operator=(ModuleMessage&& rhs);
-
-    MessageField getField(QString key) const;
-    Topic getTopic() const;
-
-    void setField(QString key, const MessageField& field);
-    void setTopic(Topic topic);
-
-    void setFields(const QMap<QString, MessageField>& fields);
-    void setFields(QMap<QString, MessageField>&& fields);
-
-    /**
-     * @brief Removes all the fields that do not match the filter.
-     */
-    void filterFields(const QString& fieldFilter);
-
-    QString toString(bool includeTopic = false) const;
-
-private:
-    Topic topic;
-    QMap<QString, MessageField> fields;
-};
diff --git a/src/shared/Core/Message/Topic.cpp b/src/shared/Core/Message/Topic.cpp
index cbae6d08531aeaaab47a8cbc78c3209b8640bfc6..24669ba98dd1f9e514f8ab076ee043ffd3839bc3 100644
--- a/src/shared/Core/Message/Topic.cpp
+++ b/src/shared/Core/Message/Topic.cpp
@@ -2,19 +2,27 @@
 
 #include <QRegExp>
 
-Topic::Topic() : topic(""), valid(true) {}
+Topic::Topic() : topic("") {}
 
-Topic::Topic(QString str)
+Topic::Topic(QString topic) : topic(topic) {}
+
+bool Topic::operator==(const Topic& toCompare) const
 {
-    if (str.contains(QRegExp("^[A-Za-z0-9$_]+(\\/[A-Za-z0-9$_]+)*$")))
-    {
-        topic = str;
-        valid = true;
-    }
-    else
-    {
-        valid = false;
-    }
+    // Always true if the current topic is a pure wildcard
+    if (topic == "*" || topic == "?")
+        return true;
+
+    // If the current topic isn't a wildcard then the topic must match
+    if (!isWildcard())
+        return topic == toCompare.toString();
+
+    // If the current topic is a wildcard then only the prefix must match
+    return toCompare.toString().startsWith(getPrefix().toString());
+}
+
+bool Topic::operator<(const Topic& toCompare) const
+{
+    return topic < toCompare.topic;
 }
 
 Topic Topic::getParent() const
@@ -29,6 +37,29 @@ Topic Topic::getRoot() const
     return idx == -1 ? Topic(topic) : Topic(topic.left(idx));
 }
 
-bool Topic::isValid() const { return valid; }
+Topic Topic::getPrefix() const
+{
+    if (!isWildcard())
+        return *this;
+
+    int idxAst = topic.lastIndexOf('*');
+    int idxQue = topic.lastIndexOf('?');
+
+    int idx = idxAst != -1 ? idxAst : idxQue;
+
+    return Topic(topic.left(idx));
+}
+
+bool Topic::isValid() const
+{
+    return topic.contains(QRegExp("^[A-Za-z0-9$_]+(\\/[A-Za-z0-9$_]+)*$"));
+}
+
+bool Topic::isWildcard() const
+{
+    // Check wether the last character is a wildcard
+    return topic.at(topic.size() - 1) == '*' ||
+           topic.at(topic.size() - 1) == '?';
+}
 
 QString Topic::toString() const { return topic; }
diff --git a/src/shared/Core/Message/Topic.h b/src/shared/Core/Message/Topic.h
index 5c1e72d3de273b1390fc71c0b9c87186907e4c39..a7088d501f19dda2ada03cff45ce01e6c022da69 100644
--- a/src/shared/Core/Message/Topic.h
+++ b/src/shared/Core/Message/Topic.h
@@ -2,35 +2,56 @@
 
 #include <QString>
 
-/*
- * This class defines topics for GS messages.
- *
- * Topics are strings made of alphanumerical characters and slashes '/'. For
- * example, "Prefix/Section2/Message" and "SomeMessage" are valid topics.
+/**
+ * @brief Topics are strings made of alphanumerical characters and slashes '/'.
  *
+ * For example, "Prefix/Message" and "SomeMessage" are valid topics.
  */
-
 class Topic
 {
 public:
     Topic();
-    explicit Topic(QString str);
+    explicit Topic(QString topic);
 
-    Topic(const Topic&)            = default;
-    Topic(Topic&&)                 = default;
-    Topic& operator=(const Topic&) = default;
-    Topic& operator=(Topic&&)      = default;
+    /**
+     * @brief Check if the given topic matches, also if the current is a
+     * wildcard.
+     */
+    bool operator==(const Topic& toCompare) const;
 
-    // Exact match
-    bool operator==(const Topic& topic) const;
+    bool operator<(const Topic& toCompare) const;
 
+    /**
+     * @brief Returns the parent.
+     *
+     * If the topic is Prefix/Message, returns Prefix.
+     */
     Topic getParent() const;
+
+    /**
+     * @brief Returns the topic root.
+     *
+     * If the topic is Topic/SubTopic/SubSubTopic, returns Topic.
+     */
     Topic getRoot() const;
+
+    /**
+     * @brief Removes the wildcard from a wildcard topic.
+     */
+    Topic getPrefix() const;
+
+    /**
+     * @brief True if the topic is valid.
+     */
     bool isValid() const;
 
+    /**
+     * @brief Returns true if the topic is a wildcard.
+     */
+    bool isWildcard() const;
+
     QString toString() const;
 
 private:
     QString topic;
-    bool valid;
 };
diff --git a/src/shared/Core/Message/TopicAndFieldFilter.cpp b/src/shared/Core/Message/TopicAndFieldFilter.cpp
deleted file mode 100644
index fb6929f72fa196d53e8c84a7e407086423508f84..0000000000000000000000000000000000000000
--- a/src/shared/Core/Message/TopicAndFieldFilter.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "TopicAndFieldFilter.h"
-
-TopicAndFieldFilter::TopicAndFieldFilter()
-    : topicFilter(TopicFilter::any()), fieldFilter("")
-{
-}
-
-TopicAndFieldFilter::TopicAndFieldFilter(const QString& topicFilter,
-                                         const QString& fieldFilter)
-    : topicFilter(topicFilter), fieldFilter(fieldFilter)
-{
-}
-
-TopicAndFieldFilter::TopicAndFieldFilter(const TopicFilter& topicFilter,
-                                         const QString& fieldFilter)
-    : topicFilter(topicFilter), fieldFilter(fieldFilter)
-{
-}
-
-bool TopicAndFieldFilter::operator==(const TopicAndFieldFilter& rhs) const
-{
-    return topicFilter == rhs.topicFilter && fieldFilter == rhs.fieldFilter;
-}
-
-bool TopicAndFieldFilter::matchTopic(const Topic& topic) const
-{
-    return topicFilter.match(topic);
-}
-
-bool TopicAndFieldFilter::matchMessage(const ModuleMessage& message,
-                                       MessageField& field) const
-{
-    // Check if the message matches the topic
-    if (!matchTopic(message.getTopic()))
-        return false;
-
-    // If the field filter is empty, the message is transformed into a single
-    // string field
-    if (fieldFilter.isEmpty())
-        field = MessageField(message.toString());
-    else
-        field = message.getField(fieldFilter);
-
-    return true;
-}
-
-bool TopicAndFieldFilter::filterMessage(ModuleMessage& message) const
-{
-    // Check if the message matches the topic
-    if (!matchTopic(message.getTopic()))
-        return false;
-
-    // Then filter the message if the field filter is not empty
-    if (!fieldFilter.isEmpty())
-        message.filterFields(fieldFilter);
-
-    return true;
-}
-
-TopicFilter TopicAndFieldFilter::getTopicFilter() const { return topicFilter; }
-
-QString TopicAndFieldFilter::getFieldFilter() const { return fieldFilter; }
-
-bool TopicAndFieldFilter::isFullFilter() const
-{
-    return !fieldFilter.isEmpty();
-}
-
-QString TopicAndFieldFilter::toString() const
-{
-    return topicFilter.toString() + "." +
-           (fieldFilter.isEmpty() ? "*" : fieldFilter);
-}
-
-TopicAndFieldFilter TopicAndFieldFilter::fromStringUnsafe(const QString& str)
-{
-    int idx = str.indexOf('.');
-    if (idx == -1)
-    {
-        return TopicAndFieldFilter(TopicFilter(str));
-    }
-
-    QString field = str.mid(idx + 1);
-    return TopicAndFieldFilter(TopicFilter(str.mid(0, idx)),
-                               field == "*" ? "" : field);
-}
diff --git a/src/shared/Core/Message/TopicAndFieldFilter.h b/src/shared/Core/Message/TopicAndFieldFilter.h
deleted file mode 100644
index a93a7b9272bf2238f2eac2e3d14cc784ad710b7c..0000000000000000000000000000000000000000
--- a/src/shared/Core/Message/TopicAndFieldFilter.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#pragma once
-
-#include "MessageField.h"
-#include "ModuleMessage.h"
-#include "TopicFilter.h"
-
-/**
- * @brief Represents an expressions that can match against topics and fields.
- *
- * It can also not select a certain field, in that case, when matches, it
- * returns the entire message converted to string.
- *
- * TODO: Support multiple filed matching.
- */
-class TopicAndFieldFilter
-{
-public:
-    TopicAndFieldFilter();
-    explicit TopicAndFieldFilter(const QString& topicFilter,
-                                 const QString& fieldFilter = "");
-    explicit TopicAndFieldFilter(const TopicFilter& topicFilter,
-                                 const QString& fieldFilter = "");
-    bool operator==(const TopicAndFieldFilter&) const;
-
-    /**
-     * @brief Check if the given topic is matched by the filter.
-     */
-    bool matchTopic(const Topic& topic) const;
-
-    /**
-     * @brief Extract the field from a message given the filter.
-     *
-     * @returns true if the message contained the filed.
-     */
-    bool matchMessage(const ModuleMessage& message, MessageField& field) const;
-
-    /**
-     * @brief Removes from the message all the fields that do not match the
-     * filter.
-     *
-     * @warning The provided message is changed if it matched the filter!
-     */
-    bool filterMessage(ModuleMessage& message) const;
-
-    TopicFilter getTopicFilter() const;
-    QString getFieldFilter() const;
-    bool isFullFilter() const;
-
-    QString toString() const;
-    static TopicAndFieldFilter fromStringUnsafe(const QString&);
-
-private:
-    TopicFilter topicFilter;
-    QString fieldFilter;
-};
diff --git a/src/shared/Core/Message/TopicFilter.cpp b/src/shared/Core/Message/TopicFilter.cpp
deleted file mode 100644
index 4331bea8548c5c05f5fde0eb7883f97f9618b726..0000000000000000000000000000000000000000
--- a/src/shared/Core/Message/TopicFilter.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#include "TopicFilter.h"
-
-TopicFilter::TopicFilter(const QString& expression)
-{
-    const QRegularExpression validExprRegex = QRegularExpression(
-        "^(?:([A-Za-z0-9_]+)\\/)?(?:([A-Za-z0-9_]+)\\/?)?([*?]?)$");
-
-    // Check if the string expression is valid
-    valid = validExprRegex.match(expression).hasMatch();
-
-    this->expression = expression;
-}
-
-bool TopicFilter::operator==(const TopicFilter& rhs) const
-{
-    return expression == rhs.expression;
-}
-
-bool TopicFilter::match(const Topic& topic) const
-{
-    // Always true if the filter is a pure wildcard
-    if (expression == "*" || expression == "?")
-        return true;
-
-    QString topicStr = topic.toString();
-
-    // If the filter doesn't contain a wildcard then the topic must match
-    if (!isWildcard())
-        return expression == topicStr;
-
-    // Extract the filter prefix before the last /
-    QStringRef prefix = expression.midRef(0, expression.lastIndexOf('/'));
-
-    // The topic can match only if it has the same prefix
-    if (!topicStr.startsWith(prefix) ||
-        (topicStr.size() > prefix.size() && topicStr.at(prefix.size()) != '/'))
-        return false;
-
-    return expression.at(expression.size() - 1) != '*' ||
-           topicStr.size() > prefix.size();
-}
-
-bool TopicFilter::isWildcard() const
-{
-    return !expression.isEmpty() &&
-           (expression.at(expression.size() - 1) == '*' ||
-            expression.at(expression.size() - 1) == '?');
-}
-
-bool TopicFilter::isValid() const { return valid; }
-
-QString TopicFilter::toString() const { return expression; }
-
-const TopicFilter TopicFilter::any() { return TopicFilter("*"); };
diff --git a/src/shared/Core/Message/TopicFilter.h b/src/shared/Core/Message/TopicFilter.h
deleted file mode 100644
index 2b18425020cd1ab47e4ea8a32e8d606bcf24bf30..0000000000000000000000000000000000000000
--- a/src/shared/Core/Message/TopicFilter.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#pragma once
-
-#include <QRegularExpression>
-#include <QString>
-
-#include "Topic.h"
-
-/**
- * @brief Represents expressions that can match against message topics.
- *
- * They can contain wildcard symbols * and ? as last token. For example:
- *  "*" and "?" match with all topics "Prefix/?" matches with "Prefix",
- * "Prefix/A" and "Prefix/A/B"
- *
- * The difference between * and ? is that the latter also matches when only the
- * prefix is present.
- */
-class TopicFilter
-{
-public:
-    TopicFilter(const QString& expression = "*");
-    bool operator==(const TopicFilter&) const;
-
-    TopicFilter(const TopicFilter&)            = default;
-    TopicFilter(TopicFilter&&)                 = default;
-    TopicFilter& operator=(const TopicFilter&) = default;
-    TopicFilter& operator=(TopicFilter&&)      = default;
-
-    /**
-     * @brief Returns true if the filter matches the given topic.
-     */
-    bool match(const Topic& topic) const;
-
-    /**
-     * @brief Returns true if the filter contains a wildcard.
-     */
-    bool isWildcard() const;
-
-    bool isValid() const;
-
-    QString toString() const;
-
-    static const TopicFilter any();
-
-private:
-    QString expression;
-    bool valid;
-};
diff --git a/src/shared/Core/MessageBroker/MessageBroker.cpp b/src/shared/Core/MessageBroker/MessageBroker.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9aeb1ac78744b2145239126e1af5ab2d95818e17
--- /dev/null
+++ b/src/shared/Core/MessageBroker/MessageBroker.cpp
@@ -0,0 +1,61 @@
+#include "MessageBroker.h"
+
+#include <Core/Module/Module.h>
+
+#include <QDebug>
+
+void MessageBroker::subscribe(Filter filter, Module* observer,
+                              Callback callback)
+{
+    observers.insert(filter, {observer, new Callback(std::move(callback))});
+
+    // Register the beforeDelete slot of the module to automatically remove the
+    // subscriber
+    connect(observer->getEventHandler(), &EventHandler::beforeDelete, this,
+            &MessageBroker::onModuleDeleted);
+
+    qDebug() << "Added subscription: " << filter.toString();
+}
+
+void MessageBroker::unsubscribe(Filter filter, Module* module)
+{
+    auto callbackList = observers.values(filter);
+
+    for (auto& elem : callbackList)
+    {
+        if (elem.first == module)
+            observers.remove(filter, elem);
+    }
+}
+
+void MessageBroker::publish(const Message& message)
+{
+    for (auto filter : observers.keys())
+    {
+        // If the message matches the filed, then notify all its subscribers
+        if (filter.match(message))
+        {
+            for (auto subscriber : observers.values(filter))
+            {
+                auto copy = message;
+                filter.filterMessage(copy);
+                (*subscriber.second)(copy);
+            }
+        }
+    }
+}
+
+void MessageBroker::onModuleDeleted(Module* module)
+{
+    for (auto filter : observers.keys())
+    {
+        for (auto subscriber : observers.values(filter))
+        {
+            if (subscriber.first == module)
+            {
+                observers.remove(filter, subscriber);
+                delete subscriber.second;
+            }
+        }
+    }
+}
diff --git a/src/shared/Core/MessageBroker/MessageBroker.h b/src/shared/Core/MessageBroker/MessageBroker.h
new file mode 100644
index 0000000000000000000000000000000000000000..ada2a4fc94d7c64481c0c22ccc3127b4339dc058
--- /dev/null
+++ b/src/shared/Core/MessageBroker/MessageBroker.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <Core/Message/Filter.h>
+
+#include <QObject>
+#include <functional>
+
+class Module;
+
+class MessageBroker : public QObject
+{
+    Q_OBJECT
+
+public:
+    using Callback = std::function<void(const Message& msg)>;
+
+    void subscribe(Filter filter, Module* observer, Callback callback);
+
+    /**
+     * @brief Unsubscribe the module from the filter.
+     */
+    void unsubscribe(Filter filter, Module* module);
+
+    /**
+     * @brief Publish a message to all its subscribers.
+     */
+    void publish(const Message& message);
+
+private:
+    QMultiMap<Filter, QPair<Module*, Callback*>> observers;
+
+private slots:
+    void onModuleDeleted(Module* module);
+};
diff --git a/src/shared/Core/Module.cpp b/src/shared/Core/Module/Module.cpp
similarity index 62%
rename from src/shared/Core/Module.cpp
rename to src/shared/Core/Module/Module.cpp
index 9fbfc96d736537d4be94d37d6d72155e9476a346..7cbada6621038a90184b32e42403ebf21aa7ec59 100644
--- a/src/shared/Core/Module.cpp
+++ b/src/shared/Core/Module/Module.cpp
@@ -2,6 +2,6 @@
 
 Module::Module(QWidget *parent) : QWidget(parent) {}
 
-ModuleEventsHandler *Module::getModuleEventsHandler() { return &eventsHandler; }
+EventHandler *Module::getEventHandler() { return &eventsHandler; }
 
 SkywardHubCoreProxy &Module::getCore() { return coreProxy; }
diff --git a/src/shared/Core/Module.h b/src/shared/Core/Module/Module.h
similarity index 74%
rename from src/shared/Core/Module.h
rename to src/shared/Core/Module/Module.h
index 9c76e7e23acb375b9954cbdca04fba2627a188f5..88a60502c855908f37e8e684557beacf6892af52 100644
--- a/src/shared/Core/Module.h
+++ b/src/shared/Core/Module/Module.h
@@ -1,10 +1,10 @@
 #pragma once
 
-#include <QWidget>
+#include <Core/EventHandler/EventHandler.h>
+#include <Core/SkywardHubCore.h>
+#include <Core/XmlObject.h>
 
-#include "Core/XmlObject.h"
-#include "ModuleEventsHandler.h"
-#include "SkywardHubCore.h"
+#include <QWidget>
 
 class Module : public QWidget
 {
@@ -19,12 +19,12 @@ public:
 
     // ModulesManagerProxy& getModuleManager();
     SkywardHubCoreProxy& getCore();
-    ModuleEventsHandler* getModuleEventsHandler();
+    EventHandler* getEventHandler();
 
 protected:
     // virtual void onManagerSetted(ModulesManager *manager);
 
 private:
     SkywardHubCoreProxy coreProxy;
-    ModuleEventsHandler eventsHandler;
+    EventHandler eventsHandler;
 };
diff --git a/src/shared/Core/ModuleEventsHandler.cpp b/src/shared/Core/ModuleEventsHandler.cpp
deleted file mode 100644
index 173b89eaf3ada0ff7d90d8c4d1bf741e6affcde7..0000000000000000000000000000000000000000
--- a/src/shared/Core/ModuleEventsHandler.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "ModuleEventsHandler.h"
-
-ModuleEventsHandler::ModuleEventsHandler() {}
diff --git a/src/shared/Core/ModuleMessagesBroker.cpp b/src/shared/Core/ModuleMessagesBroker.cpp
deleted file mode 100644
index 3fdc4bff0dba76f6310091768960c35db0022e0d..0000000000000000000000000000000000000000
--- a/src/shared/Core/ModuleMessagesBroker.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include "ModuleMessagesBroker.h"
-
-#include <QDebug>
-
-#include "Module.h"
-
-ModuleMessagesBroker::ModuleMessagesBroker() {}
-
-ModuleMessagesBroker::~ModuleMessagesBroker() {}
-
-void ModuleMessagesBroker::subscribe(TopicFilter topic, Module* observer,
-                                     MessageCallback callBack)
-{
-    CallbackCollection& collection =
-        topic.isWildcard() ? wildcardObservers : exactObservers;
-    collection.insert(
-        topic.toString(),
-        qMakePair(observer, new MessageCallback(std::move(callBack))));
-    connect(observer->getModuleEventsHandler(),
-            &ModuleEventsHandler::beforeDelete, this,
-            &ModuleMessagesBroker::onModuleDeleted);
-}
-
-void ModuleMessagesBroker::unsubscribe(TopicFilter topic, Module* module)
-{
-    CallbackCollection& collection =
-        topic.isWildcard() ? wildcardObservers : exactObservers;
-    QList<QPair<Module*, MessageCallback*>> callbackList =
-        collection.values(topic.toString());
-    for (auto& elem : callbackList)
-    {
-        if (elem.first == module)
-        {
-            collection.remove(topic.toString(), elem);
-            delete elem.second;
-        }
-    }
-}
-
-void ModuleMessagesBroker::publish(const ModuleMessage& msg)
-{
-    QString topic = msg.getTopic().toString();
-
-    if (exactObservers.contains(topic))
-    {
-        auto list = exactObservers.values(topic);
-        for (auto& item : list)
-        {
-            (*item.second)(msg);
-        }
-    }
-
-    for (auto& key : wildcardObservers.uniqueKeys())
-    {
-        if (TopicFilter(key).match(msg.getTopic()))
-        {
-            for (auto& item : wildcardObservers.values(key))
-            {
-                (*item.second)(msg);
-            }
-        }
-    }
-}
-
-QList<TopicFilter> ModuleMessagesBroker::getSubscriptionsOf(Module* module)
-{
-    QList<TopicFilter> topics;
-
-    for (auto it = wildcardObservers.keyValueBegin();
-         it != wildcardObservers.keyValueEnd(); ++it)
-    {
-        if (it->second.first == module)
-        {
-            topics.append(TopicFilter(it->first));
-        }
-    }
-
-    for (auto it = exactObservers.keyValueBegin();
-         it != exactObservers.keyValueEnd(); ++it)
-    {
-        if (it->second.first == module)
-        {
-            topics.append(TopicFilter(it->first));
-        }
-    }
-
-    return topics;
-}
-
-void ModuleMessagesBroker::onModuleDeleted(Module* module)
-{
-    // Deletion of modules happens so rarely that we can afford
-    // this "slow" way:
-
-    auto listOfFilters = getSubscriptionsOf(module);
-    for (TopicFilter filter : listOfFilters)
-    {
-        CallbackCollection& collection =
-            filter.isWildcard() ? wildcardObservers : exactObservers;
-        auto subList = collection.values(filter.toString());
-        for (int i = 0; i != subList.size();)
-        {
-            if (subList[i].first == module)
-            {
-                subList.removeAt(i);
-            }
-            else
-            {
-                i++;
-            }
-        }
-    }
-}
diff --git a/src/shared/Core/ModuleMessagesBroker.h b/src/shared/Core/ModuleMessagesBroker.h
deleted file mode 100644
index 056b4792f7e0dca342b857ee47464e9c18114aa2..0000000000000000000000000000000000000000
--- a/src/shared/Core/ModuleMessagesBroker.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-
-#include <QList>
-#include <QMap>
-#include <QObject>
-#include <functional>
-
-#include "Message/ModuleMessage.h"
-#include "Message/TopicFilter.h"
-
-class Module;
-
-class ModuleMessagesBroker : public QObject
-{
-    Q_OBJECT
-
-public:
-    using MessageCallback = std::function<void(const ModuleMessage& msg)>;
-    using CallbackCollection =
-        QMultiMap<QString, QPair<Module*, MessageCallback*>>;
-
-    ModuleMessagesBroker();
-    ~ModuleMessagesBroker();
-
-    void subscribe(TopicFilter topic, Module* observer,
-                   MessageCallback callBack);
-    // unsubscribe remove ALL callbacks associated with (topicFilter, module)
-    void unsubscribe(TopicFilter topic, Module* module);
-    void publish(const ModuleMessage& msg);
-
-    QList<TopicFilter> getSubscriptionsOf(Module* module);
-
-public slots:
-    void onModuleDeleted(Module* module);
-
-private:
-    CallbackCollection wildcardObservers, exactObservers;
-};
diff --git a/src/shared/Core/ModulesManager.cpp b/src/shared/Core/ModulesManager/ModulesManager.cpp
similarity index 83%
rename from src/shared/Core/ModulesManager.cpp
rename to src/shared/Core/ModulesManager/ModulesManager.cpp
index 3733f662f4f28c56fd9d27a64cb23e98494bd1c8..a4b809facd58ccee8e737d3f9026c8502cadb5c7 100644
--- a/src/shared/Core/ModulesManager.cpp
+++ b/src/shared/Core/ModulesManager/ModulesManager.cpp
@@ -1,17 +1,17 @@
 #include "ModulesManager.h"
 
+#include <Components/ModulesPicker/ModulesPicker.h>
+#include <Components/SaveConfigurationDialog/SaveConfigurationDialog.h>
+#include <Core/Module/Module.h>
+#include <Core/XmlObject.h>
+#include <Modules/SkywardHubStrings.h>
+
 #include <QDebug>
 #include <QDir>
 #include <QInputDialog>
 #include <QMessageBox>
 #include <QStandardPaths>
 
-#include "Components/ModulesPicker/ModulesPicker.h"
-#include "Components/SaveConfigurationDialog/SaveConfigurationDialog.h"
-#include "Core/Module.h"
-#include "Core/XmlObject.h"
-#include "Modules/SkywardHubStrings.h"
-
 ModulesList ModulesManager::modulesListHandler;
 
 ModulesManager::ModulesManager() {}
@@ -75,7 +75,7 @@ void ModulesManager::setModules(QList<Module*> modules)
     for (i = 0; i < pages.count() && i < modules.count(); i++)
     {
         Module* old = pages[i];
-        emit pages[i]->getModuleEventsHandler()->replaceMeWith(old, modules[i]);
+        emit pages[i]->getEventHandler()->replaceMeWith(old, modules[i]);
     }
     if (i < pages.count())
     {
@@ -135,39 +135,33 @@ void ModulesManager::connectModule(Module* module)
 {
     if (module)
     {
-        connect(module->getModuleEventsHandler(),
-                &ModuleEventsHandler::contextMenuRequest, this,
-                &ModulesManager::onContextMenuRequest);
-        connect(module->getModuleEventsHandler(),
-                &ModuleEventsHandler::beforeDelete, this,
+        connect(module->getEventHandler(), &EventHandler::contextMenuRequest,
+                this, &ModulesManager::onContextMenuRequest);
+        connect(module->getEventHandler(), &EventHandler::beforeDelete, this,
                 &ModulesManager::onModuleDeleted);
-        connect(module->getModuleEventsHandler(),
-                &ModuleEventsHandler::replaceMeWith, this,
+        connect(module->getEventHandler(), &EventHandler::replaceMeWith, this,
                 &ModulesManager::onReplaceMeWith);
     }
 
-    // connect(module->getModuleEventsHandler(),&ModuleEventsHandler::replaceMeWithModules,this,&ModulesManager::openWindows);
+    // connect(module->getEventHandler(),&EventHandler::replaceMeWithModules,this,&ModulesManager::openWindows);
 }
 
 void ModulesManager::disconnectModule(Module* module)
 {
     if (module)
     {
-        disconnect(module->getModuleEventsHandler(),
-                   &ModuleEventsHandler::contextMenuRequest, this,
-                   &ModulesManager::onContextMenuRequest);
-        disconnect(module->getModuleEventsHandler(),
-                   &ModuleEventsHandler::beforeDelete, this,
+        disconnect(module->getEventHandler(), &EventHandler::contextMenuRequest,
+                   this, &ModulesManager::onContextMenuRequest);
+        disconnect(module->getEventHandler(), &EventHandler::beforeDelete, this,
                    &ModulesManager::onModuleDeleted);
-        disconnect(module->getModuleEventsHandler(),
-                   &ModuleEventsHandler::replaceMeWith, this,
-                   &ModulesManager::onReplaceMeWith);
+        disconnect(module->getEventHandler(), &EventHandler::replaceMeWith,
+                   this, &ModulesManager::onReplaceMeWith);
     }
 }
 
 void ModulesManager::onModuleDeleted(Module* deletedModule)
 {
-    emit deletedModule->getModuleEventsHandler()->replaceMeWith(
+    emit deletedModule->getEventHandler()->replaceMeWith(
         deletedModule, instantiateDefaultModule());
 }
 
diff --git a/src/shared/Core/ModulesManager.h b/src/shared/Core/ModulesManager/ModulesManager.h
similarity index 100%
rename from src/shared/Core/ModulesManager.h
rename to src/shared/Core/ModulesManager/ModulesManager.h
diff --git a/src/shared/Core/SkywardHubCore.cpp b/src/shared/Core/SkywardHubCore.cpp
index dbc0891ad909d8464f91338d4bc454ec76e29e66..723ed1292491cd9a92f8d5da372301ff0f0624be 100644
--- a/src/shared/Core/SkywardHubCore.cpp
+++ b/src/shared/Core/SkywardHubCore.cpp
@@ -1,20 +1,19 @@
 #include "SkywardHubCore.h"
 
+#include <Core/EventHandler/EventHandler.h>
+#include <Core/MessageBroker/MessageBroker.h>
+#include <Core/Module/Module.h>
+#include <Core/ModulesManager/ModulesManager.h>
 #include <Modules/SkywardHubStrings.h>
 
 #include <QDir>
 #include <QMessageBox>
 
-#include "Module.h"
-#include "ModuleEventsHandler.h"
-#include "ModuleMessagesBroker.h"
-#include "ModulesManager.h"
-
 SkywardHubCore::SkywardHubCore()
 {
-    modulesManager       = new ModulesManager();
-    moduleEventsHandler  = new ModuleEventsHandler();
-    moduleMessagesBroker = new ModuleMessagesBroker();
+    modulesManager      = new ModulesManager();
+    moduleEventHandler  = new EventHandler();
+    moduleMessageBroker = new MessageBroker();
 }
 
 SkywardHubCore::~SkywardHubCore()
@@ -23,13 +22,13 @@ SkywardHubCore::~SkywardHubCore()
     {
         delete modulesManager;
     }
-    if (moduleEventsHandler)
+    if (moduleEventHandler)
     {
-        delete moduleEventsHandler;
+        delete moduleEventHandler;
     }
-    if (moduleMessagesBroker)
+    if (moduleMessageBroker)
     {
-        delete moduleMessagesBroker;
+        delete moduleMessageBroker;
     }
 }
 
@@ -99,15 +98,12 @@ void SkywardHubCore::loadFirstPage()
     modulesManager->openNewEmptyWindow();
 }
 
-ModuleMessagesBroker *SkywardHubCore::getModuleMessagesBroker()
+MessageBroker *SkywardHubCore::getMessageBroker()
 {
-    return moduleMessagesBroker;
+    return moduleMessageBroker;
 }
 
-ModuleEventsHandler *SkywardHubCore::getModuleEventsHandler()
-{
-    return moduleEventsHandler;
-}
+EventHandler *SkywardHubCore::getEventHandler() { return moduleEventHandler; }
 
 ModulesManager *SkywardHubCore::getModulesManager() { return modulesManager; }
 
diff --git a/src/shared/Core/SkywardHubCore.h b/src/shared/Core/SkywardHubCore.h
index 528fe3fcc24a48ad72cf9d89327ed01fdbf9e490..41d61678597ac0c164ba806deb6705b8db2990c2 100644
--- a/src/shared/Core/SkywardHubCore.h
+++ b/src/shared/Core/SkywardHubCore.h
@@ -5,8 +5,8 @@
 #include "XmlObject.h"
 
 class ModulesManager;
-class ModuleEventsHandler;
-class ModuleMessagesBroker;
+class EventHandler;
+class MessageBroker;
 class Module;
 
 class SkywardHubCore : public QObject
@@ -20,8 +20,8 @@ public:
     void init();
 
     ModulesManager *getModulesManager();
-    ModuleEventsHandler *getModuleEventsHandler();
-    ModuleMessagesBroker *getModuleMessagesBroker();
+    EventHandler *getEventHandler();
+    MessageBroker *getMessageBroker();
 
     XmlObject getSettings() const;
 
@@ -34,9 +34,9 @@ protected:
     void loadFirstPage();
 
 private:
-    ModulesManager *modulesManager             = nullptr;
-    ModuleEventsHandler *moduleEventsHandler   = nullptr;
-    ModuleMessagesBroker *moduleMessagesBroker = nullptr;
+    ModulesManager *modulesManager     = nullptr;
+    EventHandler *moduleEventHandler   = nullptr;
+    MessageBroker *moduleMessageBroker = nullptr;
 
     XmlObject settings;
 };
diff --git a/src/shared/Modules/CommandPad/CommandPad.cpp b/src/shared/Modules/CommandPad/CommandPad.cpp
index 62dbeac5e1b58e3378ab6653ef9ad6f46b02f453..9a1c50055bc63e79bb169e66ea4cd8afda13fc2b 100644
--- a/src/shared/Modules/CommandPad/CommandPad.cpp
+++ b/src/shared/Modules/CommandPad/CommandPad.cpp
@@ -91,7 +91,7 @@ void CommandPad::setupUi()
                 if (formElements.contains(key))
                 {
                     auto message = formElements[key]->prepareMessage(key);
-                    getCore()->getModuleMessagesBroker()->publish(message);
+                    getCore()->getMessageBroker()->publish(message);
                 }
             });
 }
diff --git a/src/shared/Modules/CommandPad/MessageFormElement.cpp b/src/shared/Modules/CommandPad/MessageFormElement.cpp
index 5d3fb2952a782d24d6d3401b5addff699821d711..2dc5d4d3e26d29693f1bc81b6a57e1afa249a7d5 100644
--- a/src/shared/Modules/CommandPad/MessageFormElement.cpp
+++ b/src/shared/Modules/CommandPad/MessageFormElement.cpp
@@ -241,29 +241,28 @@ void MessageFormElement::removeFromGridLayout(QGridLayout* layout)
     }
 }
 
-ModuleMessage MessageFormElement::prepareMessage(const QString& messageId)
+Message MessageFormElement::prepareMessage(const QString& messageId)
 {
-    ModuleMessage message(
-        Topic{SkywardHubStrings::commandsTopic + "/" + messageId});
+    Message message(Topic{SkywardHubStrings::commandsTopic + "/" + messageId});
 
     for (auto key : comboBoxMap.keys())
     {
         auto comboBox = comboBoxMap[key].second;
-        auto msg      = MessageField{(uint64_t)comboBox->currentData().toInt()};
+        auto msg      = Field{(uint64_t)comboBox->currentData().toInt()};
         message.setField(key, msg);
     }
 
     for (auto key : floatMap.keys())
     {
         auto floatField = std::get<1>(floatMap[key]);
-        auto msg        = MessageField{floatField->text().toDouble()};
+        auto msg        = Field{floatField->text().toDouble()};
         message.setField(key, msg);
     }
 
     for (auto key : integerMap.keys())
     {
         auto integerField = std::get<1>(integerMap[key]);
-        auto msg = MessageField{(uint64_t)integerField->text().toInt()};
+        auto msg          = Field{(uint64_t)integerField->text().toInt()};
         message.setField(key, msg);
     }
 
diff --git a/src/shared/Modules/CommandPad/MessageFormElement.h b/src/shared/Modules/CommandPad/MessageFormElement.h
index dc736fbd7eff0fe0c1b92efcba791859ed4fe03f..4a13361af54504865fa31f6a17935e6290a818ef 100644
--- a/src/shared/Modules/CommandPad/MessageFormElement.h
+++ b/src/shared/Modules/CommandPad/MessageFormElement.h
@@ -1,6 +1,6 @@
 #pragma once
 
-#include <Core/Message/ModuleMessage.h>
+#include <Core/Message/Message.h>
 #include <Core/XmlObject.h>
 
 #include <QComboBox>
@@ -52,7 +52,7 @@ public:
 
     void removeFromGridLayout(QGridLayout* layout);
 
-    ModuleMessage prepareMessage(const QString& messageId);
+    Message prepareMessage(const QString& messageId);
 
 private:
     QMap<QString, QPair<QLabel*, QComboBox*>> comboBoxMap;
diff --git a/src/shared/Modules/CompactCommandPad/CommandSelector.cpp b/src/shared/Modules/CompactCommandPad/CommandSelector.cpp
index 644574f35a150f1fa4bddfe86e98311d7967e5b8..bdff12d32c77404f9a3060bbad684b97e00626fc 100644
--- a/src/shared/Modules/CompactCommandPad/CommandSelector.cpp
+++ b/src/shared/Modules/CompactCommandPad/CommandSelector.cpp
@@ -61,7 +61,7 @@ void CommandSelector::fromXmlObject(const XmlObject& obj)
     }
 }
 
-bool CommandSelector::getSelection(QString& label, ModuleMessage& message,
+bool CommandSelector::getSelection(QString& label, Message& message,
                                    long& continuosSendTimeout)
 {
     message              = selectedMessage;
diff --git a/src/shared/Modules/CompactCommandPad/CommandSelector.h b/src/shared/Modules/CompactCommandPad/CommandSelector.h
index d8d16e577243a547eb1f40ba58bdf5447b384a51..a56ecf5caa454a8c2b1cc36ebc2c988e1d1ae82e 100644
--- a/src/shared/Modules/CompactCommandPad/CommandSelector.h
+++ b/src/shared/Modules/CompactCommandPad/CommandSelector.h
@@ -25,7 +25,7 @@ public:
     XmlObject toXmlObject(XmlObject& obj);
     void fromXmlObject(const XmlObject& xmlObject);
 
-    bool getSelection(QString& label, ModuleMessage& message,
+    bool getSelection(QString& label, Message& message,
                       long& continuosSendTimeout);
 
 private:
@@ -42,7 +42,7 @@ private:
 
     bool selected = false;
     QString selectedLabel;
-    ModuleMessage selectedMessage;
+    Message selectedMessage;
 
     DefaultModule* parent;
 };
diff --git a/src/shared/Modules/CompactCommandPad/CompactCommandPad.cpp b/src/shared/Modules/CompactCommandPad/CompactCommandPad.cpp
index 5094fbadda4c13b66804430faee4252386baa51e..76b275f7ad4b3c116ea22ddaad0b86daafb5611c 100644
--- a/src/shared/Modules/CompactCommandPad/CompactCommandPad.cpp
+++ b/src/shared/Modules/CompactCommandPad/CompactCommandPad.cpp
@@ -104,7 +104,7 @@ void CompactCommandPad::setupUi()
 
 void CompactCommandPad::send()
 {
-    getCore()->getModuleMessagesBroker()->publish(selectedMessage);
+    getCore()->getMessageBroker()->publish(selectedMessage);
 }
 
 void CompactCommandPad::addCustomActionsToMenu()
diff --git a/src/shared/Modules/CompactCommandPad/CompactCommandPad.h b/src/shared/Modules/CompactCommandPad/CompactCommandPad.h
index 6dba4910d4083d49abbe4f3c8424ec153dde23a0..7b1e5aea926acdbcc799df4882bfec8de081f9f1 100644
--- a/src/shared/Modules/CompactCommandPad/CompactCommandPad.h
+++ b/src/shared/Modules/CompactCommandPad/CompactCommandPad.h
@@ -33,5 +33,5 @@ private:
     QString label;
     bool selected;
     long continuosSendTimeout;
-    ModuleMessage selectedMessage;
+    Message selectedMessage;
 };
diff --git a/src/shared/Modules/CompactCommandPad/SendThread.cpp b/src/shared/Modules/CompactCommandPad/SendThread.cpp
index 89bab6c5d2e0bb749a74660806c0af70035b6a33..9840a83765948aac700bd47b04288fbe043566b9 100644
--- a/src/shared/Modules/CompactCommandPad/SendThread.cpp
+++ b/src/shared/Modules/CompactCommandPad/SendThread.cpp
@@ -1,7 +1,6 @@
 #include "SendThread.h"
 
-SendThread::SendThread(ModuleMessagesBroker* broker, const ModuleMessage& msg,
-                       long timeout)
+SendThread::SendThread(MessageBroker* broker, const Message& msg, long timeout)
     : broker(broker), msg(msg), timeout(timeout), toStop(false)
 {
     connect(this, &SendThread::finished, this, &SendThread::deleteLater);
diff --git a/src/shared/Modules/CompactCommandPad/SendThread.h b/src/shared/Modules/CompactCommandPad/SendThread.h
index 4ef3be8642a2e58f8b7fc982039c900899cd6761..51f7ceeddf4c35ab0d58350fba51b31ede17fb9c 100644
--- a/src/shared/Modules/CompactCommandPad/SendThread.h
+++ b/src/shared/Modules/CompactCommandPad/SendThread.h
@@ -1,22 +1,21 @@
 #pragma once
 
-#include <QThread>
+#include <Core/MessageBroker/MessageBroker.h>
 
-#include "Core/ModuleMessagesBroker.h"
+#include <QThread>
 
 class SendThread : public QThread
 {
 public:
-    SendThread(ModuleMessagesBroker* broker, const ModuleMessage& msg,
-               long timeout);
+    SendThread(MessageBroker* broker, const Message& msg, long timeout);
     void requestStop();
 
 protected:
     void run() override;
 
 private:
-    ModuleMessagesBroker* broker;
-    ModuleMessage msg;
+    MessageBroker* broker;
+    Message msg;
     long timeout;
     bool toStop;
 };
diff --git a/src/shared/Modules/DefaultModule/DefaultModule.cpp b/src/shared/Modules/DefaultModule/DefaultModule.cpp
index 900a1a16d908ceed12581bec022d0553a393d391..0be1f61f19135d49579c9ae90ed6f2dafd69f034 100644
--- a/src/shared/Modules/DefaultModule/DefaultModule.cpp
+++ b/src/shared/Modules/DefaultModule/DefaultModule.cpp
@@ -1,9 +1,9 @@
 #include "DefaultModule.h"
 
-#include <QCloseEvent>
+#include <Components/ContextMenuSeparator/ContextMenuSeparator.h>
+#include <Core/ModulesManager/ModulesManager.h>
 
-#include "Components/ContextMenuSeparator/ContextMenuSeparator.h"
-#include "Core/ModulesManager.h"
+#include <QCloseEvent>
 
 DefaultModule::DefaultModule(QWidget* parent) : Module(parent) {}
 
@@ -45,7 +45,7 @@ void DefaultModule::onSkywardHubContextMenuRequested(QMenu& menu,
 
     menu.addSeparator();
 
-    emit getModuleEventsHandler()->contextMenuRequest(menu, pos);
+    emit getEventHandler()->contextMenuRequest(menu, pos);
 }
 
 SkywardHubCoreProxy& DefaultModule::getCore() { return proxyCore; }
@@ -94,7 +94,7 @@ void DefaultModule::closeEvent(QCloseEvent* event)
 {
     if (event->spontaneous())
     {
-        emit getModuleEventsHandler()->beforeDelete(this);
+        emit getEventHandler()->beforeDelete(this);
         QWidget::closeEvent(event);
     }
     else
@@ -131,7 +131,7 @@ void DefaultModule::onReplaceClicked()
     Module* newModule =
         getCore()->getModulesManager()->invokeModulesPickerService();
     if (newModule != nullptr)
-        emit getModuleEventsHandler()->replaceMeWith(this, newModule);
+        emit getEventHandler()->replaceMeWith(this, newModule);
 }
 
 void DefaultModule::onCloseClicked() { close(); }
diff --git a/src/shared/Modules/DefaultModule/DefaultModule.h b/src/shared/Modules/DefaultModule/DefaultModule.h
index 9f30cdc33ebaaab7ccfe9e788c0fa2e4f2278412..c7b39e5910172f19c739bee858cf37b58dc88d05 100644
--- a/src/shared/Modules/DefaultModule/DefaultModule.h
+++ b/src/shared/Modules/DefaultModule/DefaultModule.h
@@ -1,10 +1,10 @@
 #pragma once
 
-#include "Components/ErrorDisplayer/ErrorDisplayer.h"
-#include "Core/Module.h"
-#include "Core/SkywardHubCore.h"
-#include "Modules/MainWindow/Window.h"
-#include "Modules/ModuleInfo.h"
+#include <Components/ErrorDisplayer/ErrorDisplayer.h>
+#include <Core/Module/Module.h>
+#include <Core/SkywardHubCore.h>
+#include <Modules/MainWindow/Window.h>
+#include <Modules/ModuleInfo.h>
 
 class DefaultModule : public Module
 {
diff --git a/src/shared/Modules/Empty/EmptyModule.cpp b/src/shared/Modules/Empty/EmptyModule.cpp
index f9e544b4035803f6612f6e6b94622e94887f2e37..e6e5a25506323d1b5922041a431750fe1b4e14b4 100644
--- a/src/shared/Modules/Empty/EmptyModule.cpp
+++ b/src/shared/Modules/Empty/EmptyModule.cpp
@@ -1,11 +1,12 @@
 #include "EmptyModule.h"
 
+#include <Core/ModulesManager/ModulesManager.h>
+
 #include <QAction>
 #include <QMessageBox>
 #include <QPoint>
 
 #include "Components/ContextMenuSeparator/ContextMenuSeparator.h"
-#include "Core/ModulesManager.h"
 #include "ui_EmptyModule.h"
 
 EmptyModule::EmptyModule() : DefaultModule(), ui(new Ui::EmptyModule)
diff --git a/src/shared/Modules/Empty/EmptyModule.h b/src/shared/Modules/Empty/EmptyModule.h
index df01964b86ada54307e19b1cf758d08350149098..5f2696d20a0662095ebc11b6dc44f085b14e9251 100644
--- a/src/shared/Modules/Empty/EmptyModule.h
+++ b/src/shared/Modules/Empty/EmptyModule.h
@@ -1,12 +1,12 @@
 #pragma once
 
+#include <Core/Module/Module.h>
+#include <Modules/DefaultModule/DefaultModule.h>
+
 #include <QMenu>
 #include <QSharedPointer>
 #include <QWidget>
 
-#include "Core/Module.h"
-#include "Modules/DefaultModule/DefaultModule.h"
-
 namespace Ui
 {
 class EmptyModule;
diff --git a/src/shared/Modules/FileStream/FileStreamModule.cpp b/src/shared/Modules/FileStream/FileStreamModule.cpp
index 63693c28f42037b6a57c5e520a0a4bd7ba12f9e5..609d61b7846dddcf892abc1cdcd40174199ae8eb 100644
--- a/src/shared/Modules/FileStream/FileStreamModule.cpp
+++ b/src/shared/Modules/FileStream/FileStreamModule.cpp
@@ -1,12 +1,13 @@
 #include "FileStreamModule.h"
 
+#include <Core/MessageBroker/MessageBroker.h>
+
 #include <QDebug>
 #include <QDesktopServices>
 #include <QDir>
 #include <QMessageBox>
 #include <QUrl>
 
-#include "Core/ModuleMessagesBroker.h"
 #include "Modules/SkywardHubStrings.h"
 #include "ui_FileStreamModule.h"
 
@@ -92,7 +93,7 @@ QString FileStreamModule::getTopicName() const
 
 void FileStreamModule::resetTopicName() { ui->topicName_lineEdit->clear(); }
 
-void FileStreamModule::onMsgReceived(const ModuleMessage& msg)
+void FileStreamModule::onMsgReceived(const Message& msg)
 {
     //    if(file.isOpen() ){
     //        QTextStream out(&file);
@@ -131,9 +132,9 @@ void FileStreamModule::onStartClicked()
     disableOnStartElement();
     for (int i = 0; i < topicViewsList.count(); i++)
     {
-        getCore()->getModuleMessagesBroker()->subscribe(
-            topicViewsList[i]->text().trimmed(), this,
-            [this](const ModuleMessage& msg) { onMsgReceived(msg); });
+        getCore()->getMessageBroker()->subscribe(
+            Filter::fromString(topicViewsList[i]->text().trimmed()), this,
+            [this](const Message& msg) { onMsgReceived(msg); });
         topicViewsList[i]->setEnabled(false);
     }
 }
@@ -146,8 +147,8 @@ void FileStreamModule::onStopClicked()
 
     for (int i = 0; i < topicViewsList.count(); i++)
     {
-        getCore()->getModuleMessagesBroker()->unsubscribe(
-            topicViewsList[i]->text().trimmed(), this);
+        getCore()->getMessageBroker()->unsubscribe(
+            Filter::fromString(topicViewsList[i]->text().trimmed()), this);
         topicViewsList[i]->setEnabled(true);
     }
 }
@@ -217,8 +218,8 @@ void FileStreamModule::deleteAllTopicViews()
 {
     for (int i = 0; i < topicViewsList.count(); i++)
     {
-        getCore()->getModuleMessagesBroker()->unsubscribe(
-            topicViewsList[i]->text().trimmed(), this);
+        getCore()->getMessageBroker()->unsubscribe(
+            Filter::fromString(topicViewsList[i]->text().trimmed()), this);
         ui->topics_layout->removeWidget(topicViewsList[i]);
         topicViewsList[i]->deleteLater();
     }
diff --git a/src/shared/Modules/FileStream/FileStreamModule.h b/src/shared/Modules/FileStream/FileStreamModule.h
index 6054cc845f835c447ede1c75ba509f966860c3e3..1e778559e1d41624e61619c783b5ade8b429b4b0 100644
--- a/src/shared/Modules/FileStream/FileStreamModule.h
+++ b/src/shared/Modules/FileStream/FileStreamModule.h
@@ -1,12 +1,12 @@
 #pragma once
 
+#include <Core/Message/Message.h>
+#include <Modules/DefaultModule/DefaultModule.h>
+
 #include <QFile>
 #include <QLineEdit>
 #include <QWidget>
 
-#include "Core/Message/ModuleMessage.h"
-#include "Modules/DefaultModule/DefaultModule.h"
-
 namespace Ui
 {
 class FileStreamModule;
@@ -30,7 +30,7 @@ protected:
     QString getFilePath() const;
     QString getTopicName() const;
     void resetTopicName();
-    void onMsgReceived(const ModuleMessage& msg);
+    void onMsgReceived(const Message& msg);
 
     void onAddTopicClicked();
     void onStartClicked();
diff --git a/src/shared/Modules/Graph/Graph.cpp b/src/shared/Modules/Graph/Graph.cpp
index 914dc8313f1e1a0d5719d10b58f9f3fd4c5000e8..17c56cbf1d1418d0985e1ca41477838c32c02ca3 100644
--- a/src/shared/Modules/Graph/Graph.cpp
+++ b/src/shared/Modules/Graph/Graph.cpp
@@ -2,7 +2,7 @@
 
 #include <Components/ContextMenuSeparator/ContextMenuSeparator.h>
 #include <Components/SubscriptionsPanel/SubscriptionsPanel.h>
-#include <Core/ModuleMessagesBroker.h>
+#include <Core/MessageBroker/MessageBroker.h>
 
 #include <QTimer>
 #include <algorithm>
@@ -16,8 +16,9 @@ Graph::Graph(QWidget* parent) : DefaultModule(parent)
     updaterTimer.setSingleShot(false);
     updaterTimer.start(updatePeriod);
 
-    getCore()->getModuleMessagesBroker()->subscribe(
-        {"*"}, this, [this](const ModuleMessage& msg) { onMsgReceived(msg); });
+    getCore()->getMessageBroker()->subscribe(Filter::fromString("*"), this,
+                                             [this](const Message& msg)
+                                             { onMsgReceived(msg); });
 }
 
 Graph::~Graph() {}
@@ -69,8 +70,7 @@ void Graph::fromXmlObject(const XmlObject& obj)
 
             if (child.getObjectName() == "subscription")
             {
-                auto filter = TopicAndFieldFilter::fromStringUnsafe(
-                    child.getAttribute("filter"));
+                auto filter = Filter::fromString(child.getAttribute("filter"));
                 onSubscriptionAdded(filter);
             }
         }
@@ -107,7 +107,7 @@ void Graph::onStopClicked(bool checked)
 
 void Graph::onFollowClicked(bool checked) { following = checked; }
 
-void Graph::onSubscriptionAdded(const TopicAndFieldFilter& filter)
+void Graph::onSubscriptionAdded(const Filter& filter)
 {
     if (!filters.contains(filter))
     {
@@ -126,7 +126,7 @@ void Graph::onSubscriptionAdded(const TopicAndFieldFilter& filter)
     }
 }
 
-void Graph::onSubscriptionRemoved(const TopicAndFieldFilter& filter)
+void Graph::onSubscriptionRemoved(const Filter& filter)
 {
     if (filters.contains(filter))
     {
@@ -186,24 +186,24 @@ void Graph::onUpdateTimerTick()
     }
 }
 
-void Graph::onMsgReceived(const ModuleMessage& msg)
+void Graph::onMsgReceived(const Message& msg)
 {
     if (stopped)
         return;
 
-    MessageField value;
+    // TODO
 
     for (auto filter : filters)
     {
-        if (filter.matchMessage(msg, value))
+        if (filter.match(msg))
         {
             int index = filters.indexOf(filter);
 
             QVector<double>& bufferX = buffersX[index];
             QVector<double>& bufferY = buffersY[index];
 
-            double x = msg.getField("timestamp").getUInteger(0) / 1e6;
-            double y = value.getDouble(0);
+            double x = msg.getField("timestamp").getUnsignedInteger() / 1e6;
+            double y = 2;  // TODO
 
             // Check if the timestamp resets
             if (bufferX.last() < x)
@@ -282,5 +282,5 @@ void Graph::onCustomContextMenuRequested(const QPoint& pos)
     // Add a separator
     menu.addSeparator();
 
-    emit getModuleEventsHandler()->contextMenuRequest(menu, mapToGlobal(pos));
+    emit getEventHandler()->contextMenuRequest(menu, mapToGlobal(pos));
 }
\ No newline at end of file
diff --git a/src/shared/Modules/Graph/Graph.h b/src/shared/Modules/Graph/Graph.h
index dacb40a904a782aa8be9b988705a65987a9d8dce..edb741816d2b0416d6fcb517702bc260e6c59f7b 100644
--- a/src/shared/Modules/Graph/Graph.h
+++ b/src/shared/Modules/Graph/Graph.h
@@ -1,8 +1,8 @@
 #pragma once
 
-#include <Core/Message/ModuleMessage.h>
-#include <Core/Message/TopicAndFieldFilter.h>
-#include <Core/Module.h>
+#include <Core/Message/Filter.h>
+#include <Core/Message/Message.h>
+#include <Core/Module/Module.h>
 #include <Core/QCustomPlot/QCustomPlot.h>
 #include <Modules/DefaultModule/DefaultModule.h>
 
@@ -29,10 +29,10 @@ private slots:
     void onClearClicked();
     void onStopClicked(bool checked);
     void onFollowClicked(bool checked);
-    void onSubscriptionAdded(const TopicAndFieldFilter& filter);
-    void onSubscriptionRemoved(const TopicAndFieldFilter& filter);
+    void onSubscriptionAdded(const Filter& filter);
+    void onSubscriptionRemoved(const Filter& filter);
     void onUpdateTimerTick();
-    void onMsgReceived(const ModuleMessage& msg);
+    void onMsgReceived(const Message& msg);
 
 private:
     void setupUi();
@@ -41,7 +41,7 @@ private:
 
     QCustomPlot* plot;
 
-    QList<TopicAndFieldFilter> filters;
+    QList<Filter> filters;
     QList<QCPGraph*> graphs;
     QList<QVector<double>> buffersX;
     QList<QVector<double>> buffersY;
diff --git a/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.cpp b/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.cpp
index e2e985a8ffdd3b64e9e6635353d33e9d063bbdec..c43042b8e5117b753f4b12cfdff80638ec8411bf 100644
--- a/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.cpp
+++ b/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.cpp
@@ -1,5 +1,6 @@
 #include "IncomingMessagesViewerModule.h"
 
+#include <QDebug>
 #include <QHBoxLayout>
 
 #include "Components/SubscriptionsPanel/SubscriptionsPanel.h"
@@ -9,62 +10,12 @@ IncomingMessagesViewerModule::IncomingMessagesViewerModule(QWidget* parent)
 {
     setupUi();
     defaultContextMenuSetup();
-
-    getCore()->getModuleMessagesBroker()->subscribe(
-        {"*"}, this,
-        [this](const ModuleMessage& msg)
-        {
-            MessageField value;
-            for (auto it = filters.begin(); it != filters.end(); ++it)
-            {
-                // Show only the messages and fields matched by the filters
-                if (it->matchMessage(msg, value))
-                {
-                    if (keepOnlyLastMessage)
-                        edit->setText("");
-
-                    // Save the old text
-                    QString oldText = edit->toPlainText().mid(0, 10000);
-
-                    // Prepare the new text
-                    QString time = "";
-
-                    if (useTimestamp)
-                    {
-                        // If available show the timestamp
-                        auto timestamp = msg.getField("timestamp");
-                        if (timestamp.getType() == MessageField::Type::UINTEGER)
-                            time += "[" +
-                                    QString::number(
-                                        (float)timestamp.getUInteger(0) / 1e6,
-                                        'f', 1) +
-                                    "] ";
-                        else
-                            time += "[ ? ]";
-                    }
-                    else
-                    {
-                        time += "[" +
-                                QTime::currentTime().toString("hh.mm.ss") +
-                                "] ";
-                    }
-
-                    QString topic = msg.getTopic().toString() +
-                                    (it->isFullFilter()
-                                         ? (QString(".") + it->getFieldFilter())
-                                         : "") +
-                                    ": ";
-
-                    // Updated the content
-                    edit->setText(time + value.getString() + "\n" + oldText);
-                }
-            }
-        });
 }
 
 IncomingMessagesViewerModule::~IncomingMessagesViewerModule()
 {
-    getCore()->getModuleMessagesBroker()->unsubscribe({"*"}, this);
+    for (auto filter : filters)
+        getCore()->getMessageBroker()->unsubscribe(filter, this);
 }
 
 QWidget* IncomingMessagesViewerModule::toWidget() { return this; }
@@ -78,8 +29,8 @@ XmlObject IncomingMessagesViewerModule::toXmlObject()
 
     for (int i = 0; i < filters.count(); i++)
     {
-        XmlObject subscription("Subscription");
-        subscription.addAttribute("Value", filters[i].toString());
+        XmlObject subscription("subscription");
+        subscription.addAttribute("filter", filters[i].toString());
         obj.addChild(subscription);
     }
 
@@ -96,25 +47,49 @@ void IncomingMessagesViewerModule::fromXmlObject(const XmlObject& xmlObject)
     for (int i = 0; i < xmlObject.childCount(); i++)
     {
         XmlObject child = xmlObject.childAt(i);
-        if (child.getObjectName() == "Subscription")
-        {
-            auto subscription = TopicAndFieldFilter::fromStringUnsafe(
-                child.getAttribute("Value"));
-            addSubscription(subscription);
-        }
+        if (child.getObjectName() == "subscription")
+            addSubscription(Filter::fromString(child.getAttribute("filter")));
     }
 }
 
-void IncomingMessagesViewerModule::addSubscription(
-    const TopicAndFieldFilter& filter)
+void IncomingMessagesViewerModule::addSubscription(const Filter& filter)
 {
+    qDebug() << "addSubscription";
     filters.append(filter);
+    getCore()->getMessageBroker()->subscribe(
+        filter, this,
+        [&](const Message& msg)
+        {
+            QString oldText = "";
+            QString time    = "";
+
+            // Save the old text
+            if (!keepOnlyLastMessage)
+                oldText = edit->toPlainText().mid(0, 10000);
+
+            if (useTimestamp)
+            {
+                // If available  show the timestamp
+                auto timestamp = msg.getField("timestamp");
+                time += "[";
+                time += QString::number(
+                    (float)timestamp.getUnsignedInteger() / 1e6, 'f', 1);
+                time += "] ";
+            }
+            else
+            {
+                time += "[" + QTime::currentTime().toString("hh.mm.ss") + "] ";
+            }
+
+            // Updated the content
+            edit->setText(time + msg.toString() + "\n" + oldText);
+        });
 }
 
-void IncomingMessagesViewerModule::removeSubscription(
-    const TopicAndFieldFilter& filter)
+void IncomingMessagesViewerModule::removeSubscription(const Filter& filter)
 {
     filters.removeAll(filter);
+    getCore()->getMessageBroker()->unsubscribe(filter, this);
 }
 
 void IncomingMessagesViewerModule::addCustomActionsToMenu()
diff --git a/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.h b/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.h
index 03b4cdce8d51568125cd7ea9a0d22e3e6a8ccbb8..4333f0a54ee78aef64710df14039032cf4735161 100644
--- a/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.h
+++ b/src/shared/Modules/IncomingMessagesViewer/IncomingMessagesViewerModule.h
@@ -1,7 +1,7 @@
 #pragma once
 
-#include "Core/Message/TopicAndFieldFilter.h"
-#include "Modules/DefaultModule/DefaultModule.h"
+#include <Core/Message/Filter.h>
+#include <Modules/DefaultModule/DefaultModule.h>
 
 class IncomingMessagesViewerModule : public DefaultModule
 {
@@ -18,14 +18,14 @@ public:
     void addCustomActionsToMenu() override;
 
 public slots:
-    void addSubscription(const TopicAndFieldFilter& filter);
-    void removeSubscription(const TopicAndFieldFilter& filter);
+    void addSubscription(const Filter& filter);
+    void removeSubscription(const Filter& filter);
 
 private:
     QTextEdit* edit;
     void setupUi();
 
-    QList<TopicAndFieldFilter> filters;
+    QList<Filter> filters;
 
     bool keepOnlyLastMessage = false;
     QAction* keepOnlyLastMessageAction;
diff --git a/src/shared/Modules/MainWindow/SkywardHubMainWindow.cpp b/src/shared/Modules/MainWindow/SkywardHubMainWindow.cpp
index 6d08441b21181c326daada867310bc6ee022d657..a7d3db720189a9a4bb4ba4563776ffbcb5f1e369 100644
--- a/src/shared/Modules/MainWindow/SkywardHubMainWindow.cpp
+++ b/src/shared/Modules/MainWindow/SkywardHubMainWindow.cpp
@@ -1,11 +1,11 @@
 #include "SkywardHubMainWindow.h"
 
+#include <Core/Module/Module.h>
+#include <Core/ModulesManager/ModulesManager.h>
+
 #include <QFile>
 #include <QMenu>
 
-#include "Core/Module.h"
-#include "Core/ModulesManager.h"
-
 SkywardHubMainWindow::SkywardHubMainWindow(QWidget* parent)
     : QMainWindow(parent)
 {
diff --git a/src/shared/Modules/MainWindow/Window.cpp b/src/shared/Modules/MainWindow/Window.cpp
index 49b50cb1e7df61a52b7a6542b5b14dd369498c88..9c32e609889d857ba0d334fafec316af09f6ba35 100644
--- a/src/shared/Modules/MainWindow/Window.cpp
+++ b/src/shared/Modules/MainWindow/Window.cpp
@@ -1,9 +1,10 @@
 #include "Window.h"
 
+#include <Core/Module/Module.h>
+#include <Core/ModulesManager/ModulesManager.h>
+
 #include <QVBoxLayout>
 
-#include "Core/Module.h"
-#include "Core/ModulesManager.h"
 #include "ui_Window.h"
 
 Window::Window(QWidget* parent) : QWidget(parent), ui(new Ui::Window)
@@ -36,18 +37,17 @@ void Window::setCentralModule(Module* value)
     if (centralModule != nullptr)
     {
         // ui->mainLayout->removeWidget(centralModule->toWidget());
-        disconnect(centralModule->getModuleEventsHandler(), &QWidget::destroyed,
-                   this, &Window::onWidgetDestroyed);
-        disconnect(centralModule->getModuleEventsHandler(),
-                   &ModuleEventsHandler::replaceMeWith, this,
+        disconnect(centralModule->getEventHandler(), &QWidget::destroyed, this,
+                   &Window::onWidgetDestroyed);
+        disconnect(centralModule->getEventHandler(),
+                   &EventHandler::replaceMeWith, this,
                    &Window::onReplaceRequested);
     }
     centralModule = value;
     ui->mainLayout->addWidget(value->toWidget());
-    connect(value->getModuleEventsHandler(), &QWidget::destroyed, this,
+    connect(value->getEventHandler(), &QWidget::destroyed, this,
             &Window::onWidgetDestroyed);
-    connect(value->getModuleEventsHandler(),
-            &ModuleEventsHandler::replaceMeWith, this,
+    connect(value->getEventHandler(), &EventHandler::replaceMeWith, this,
             &Window::onReplaceRequested);
 
     value->toWidget()->lower();
diff --git a/src/shared/Modules/Mavlink/MavlinkCommandAdapter.cpp b/src/shared/Modules/Mavlink/MavlinkCommandAdapter.cpp
index ccd7a12bd425ac3d0e0227cae5aa1066317ee4cd..7aae613c56992eb989542cef213b167bdc800ddd 100644
--- a/src/shared/Modules/Mavlink/MavlinkCommandAdapter.cpp
+++ b/src/shared/Modules/Mavlink/MavlinkCommandAdapter.cpp
@@ -1,6 +1,7 @@
 #include "MavlinkCommandAdapter.h"
 
-#include "Core/ModulesManager.h"
+#include <Core/ModulesManager/ModulesManager.h>
+
 #include "Core/XmlObject.h"
 #include "MavlinkModule.h"
 #include "MavlinkVersionHeader.h"
@@ -13,115 +14,123 @@ void MavlinkCommandAdapter::setSerialPort(QSerialPort *value)
     serial = value;
 }
 
-bool MavlinkCommandAdapter::encodeCommand(const ModuleMessage &msg,
+bool MavlinkCommandAdapter::encodeCommand(const Message &msg,
                                           mavlink_message_t &output)
 {
     QString messageName = msg.getTopic().toString().replace(
         SkywardHubStrings::commandsTopic + "/", "");
     if (messageName == "PING_TC")
     {
-        mavlink_msg_ping_tc_pack(MAV_SYS, MAV_CMP, &output,
-                                 msg.getField("timestamp").getUInteger(0));
+        mavlink_msg_ping_tc_pack(
+            MAV_SYS, MAV_CMP, &output,
+            msg.getField("timestamp").getUnsignedInteger());
         return true;
     }
     else if (messageName == "COMMAND_TC")
     {
-        mavlink_msg_command_tc_pack(MAV_SYS, MAV_CMP, &output,
-                                    msg.getField("command_id").getUInteger(0));
+        mavlink_msg_command_tc_pack(
+            MAV_SYS, MAV_CMP, &output,
+            msg.getField("command_id").getUnsignedInteger());
         return true;
     }
     else if (messageName == "SYSTEM_TM_REQUEST_TC")
     {
         mavlink_msg_system_tm_request_tc_pack(
-            MAV_SYS, MAV_CMP, &output, msg.getField("tm_id").getUInteger(0));
+            MAV_SYS, MAV_CMP, &output,
+            msg.getField("tm_id").getUnsignedInteger());
         return true;
     }
     else if (messageName == "SENSOR_TM_REQUEST_TC")
     {
         mavlink_msg_sensor_tm_request_tc_pack(
             MAV_SYS, MAV_CMP, &output,
-            msg.getField("sensor_id").getUInteger(0));
+            msg.getField("sensor_id").getUnsignedInteger());
         return true;
     }
     else if (messageName == "SERVO_TM_REQUEST_TC")
     {
         mavlink_msg_servo_tm_request_tc_pack(
-            MAV_SYS, MAV_CMP, &output, msg.getField("servo_id").getUInteger(0));
+            MAV_SYS, MAV_CMP, &output,
+            msg.getField("servo_id").getUnsignedInteger());
         return true;
     }
     else if (messageName == "SET_SERVO_ANGLE_TC")
     {
         mavlink_msg_set_servo_angle_tc_pack(
-            MAV_SYS, MAV_CMP, &output, msg.getField("servo_id").getUInteger(0),
-            msg.getField("angle").getDouble(0.0));
+            MAV_SYS, MAV_CMP, &output,
+            msg.getField("servo_id").getUnsignedInteger(),
+            msg.getField("angle").getDouble());
         return true;
     }
     else if (messageName == "WIGGLE_SERVO_TC")
     {
         mavlink_msg_wiggle_servo_tc_pack(
-            MAV_SYS, MAV_CMP, &output, msg.getField("servo_id").getUInteger(0));
+            MAV_SYS, MAV_CMP, &output,
+            msg.getField("servo_id").getUnsignedInteger());
         return true;
     }
     else if (messageName == "RESET_SERVO_TC")
     {
         mavlink_msg_reset_servo_tc_pack(
-            MAV_SYS, MAV_CMP, &output, msg.getField("servo_id").getUInteger(0));
+            MAV_SYS, MAV_CMP, &output,
+            msg.getField("servo_id").getUnsignedInteger());
         return true;
     }
     else if (messageName == "SET_REFERENCE_ALTITUDE_TC")
     {
         mavlink_msg_set_reference_altitude_tc_pack(
             MAV_SYS, MAV_CMP, &output,
-            msg.getField("ref_altitude").getDouble(0.0));
+            msg.getField("ref_altitude").getDouble());
         return true;
     }
     else if (messageName == "SET_REFERENCE_TEMPERATURE_TC")
     {
         mavlink_msg_set_reference_temperature_tc_pack(
-            MAV_SYS, MAV_CMP, &output, msg.getField("ref_temp").getDouble(0.0));
+            MAV_SYS, MAV_CMP, &output, msg.getField("ref_temp").getDouble());
         return true;
     }
     else if (messageName == "SET_DEPLOYMENT_ALTITUDE_TC")
     {
         mavlink_msg_set_deployment_altitude_tc_pack(
             MAV_SYS, MAV_CMP, &output,
-            msg.getField("dpl_altitude").getDouble(0.0));
+            msg.getField("dpl_altitude").getDouble());
         return true;
     }
     else if (messageName == "SET_ORIENTATION_TC")
     {
-        mavlink_msg_set_orientation_tc_pack(
-            MAV_SYS, MAV_CMP, &output, msg.getField("yaw").getDouble(0.0),
-            msg.getField("pitch").getDouble(0.0),
-            msg.getField("roll").getDouble(0.0));
+        mavlink_msg_set_orientation_tc_pack(MAV_SYS, MAV_CMP, &output,
+                                            msg.getField("yaw").getDouble(),
+                                            msg.getField("pitch").getDouble(),
+                                            msg.getField("roll").getDouble());
         return true;
     }
     else if (messageName == "SET_COORDINATES_TC")
     {
         mavlink_msg_set_coordinates_tc_pack(
-            MAV_SYS, MAV_CMP, &output, msg.getField("latitude").getDouble(0.0),
-            msg.getField("longitude").getDouble(0.0));
+            MAV_SYS, MAV_CMP, &output, msg.getField("latitude").getDouble(),
+            msg.getField("longitude").getDouble());
         return true;
     }
     else if (messageName == "RAW_EVENT_TC")
     {
-        mavlink_msg_raw_event_tc_pack(MAV_SYS, MAV_CMP, &output,
-                                      msg.getField("topic_id").getUInteger(0),
-                                      msg.getField("event_id").getUInteger(0));
+        mavlink_msg_raw_event_tc_pack(
+            MAV_SYS, MAV_CMP, &output,
+            msg.getField("topic_id").getUnsignedInteger(),
+            msg.getField("event_id").getUnsignedInteger());
         return true;
     }
     else if (messageName == "SET_TARGET_COORDINATES_TC")
     {
         mavlink_msg_set_target_coordinates_tc_pack(
-            MAV_SYS, MAV_CMP, &output, msg.getField("latitude").getDouble(0.0),
-            msg.getField("longitude").getDouble(0.0));
+            MAV_SYS, MAV_CMP, &output, msg.getField("latitude").getDouble(),
+            msg.getField("longitude").getDouble());
         return true;
     }
     else if (messageName == "SET_ALGORITHM_TC")
     {
         mavlink_msg_set_algorithm_tc_pack(
             MAV_SYS, MAV_CMP, &output,
-            msg.getField("algorithm_number").getUInteger(0));
+            msg.getField("algorithm_number").getUnsignedInteger());
         return true;
     }
     return false;
diff --git a/src/shared/Modules/Mavlink/MavlinkCommandAdapter.h b/src/shared/Modules/Mavlink/MavlinkCommandAdapter.h
index a26014abc297ce6774695946c298d7d7f2c13bcd..137234dbfad971ffeccd13dc3853af53f5bd5b61 100644
--- a/src/shared/Modules/Mavlink/MavlinkCommandAdapter.h
+++ b/src/shared/Modules/Mavlink/MavlinkCommandAdapter.h
@@ -1,11 +1,12 @@
 #pragma once
 
+#include <Core/Message/Message.h>
+#include <Core/ModulesManager/ModulesManager.h>
+
 #include <QMap>
 #include <QObject>
 #include <QSerialPort>
 
-#include "Core/Message/ModuleMessage.h"
-#include "Core/ModulesManager.h"
 #include "MavlinkVersionHeader.h"
 #include "MavlinkWriter.h"
 
@@ -24,7 +25,7 @@ public:
 
     void send(mavlink_message_t msg);
     void setSerialPort(QSerialPort* value);
-    bool encodeCommand(const ModuleMessage& msg, mavlink_message_t& output);
+    bool encodeCommand(const Message& msg, mavlink_message_t& output);
 
     bool produceMsgFromXml(const XmlObject& xml, mavlink_message_t* msg);
     static const int MAV_CMP = 96;
diff --git a/src/shared/Modules/Mavlink/MavlinkModule.cpp b/src/shared/Modules/Mavlink/MavlinkModule.cpp
index 7704c4c892a2d29dc4a5216895d1e56c128b5794..ecdc16fb85dfb5d6fd8394360466263e1733950c 100644
--- a/src/shared/Modules/Mavlink/MavlinkModule.cpp
+++ b/src/shared/Modules/Mavlink/MavlinkModule.cpp
@@ -1,10 +1,11 @@
 #include "MavlinkModule.h"
 
+#include <Core/MessageBroker/MessageBroker.h>
+
 #include <QDebug>
 #include <QSerialPortInfo>
 
 #include "Components/ContextMenuSeparator/ContextMenuSeparator.h"
-#include "Core/ModuleMessagesBroker.h"
 #include "Modules/SkywardHubStrings.h"
 
 MavlinkModule::MavlinkModule(QWidget *parent)
@@ -21,9 +22,9 @@ MavlinkModule::MavlinkModule(QWidget *parent)
 
     mavlinkCommandAdapter.setSerialPort(&serialPort);
 
-    getCore()->getModuleMessagesBroker()->subscribe(
-        {SkywardHubStrings::commandsTopic + "/*"}, this,
-        [this](const ModuleMessage &msg) { onCommandReceived(msg); });
+    getCore()->getMessageBroker()->subscribe(
+        Filter::fromString(SkywardHubStrings::commandsTopic + "/*"), this,
+        [this](const Message &msg) { onCommandReceived(msg); });
 }
 
 MavlinkModule::~MavlinkModule() { onStopClicked(); }
@@ -90,10 +91,10 @@ void MavlinkModule::onStopClicked()
     closePort();
 }
 
-void MavlinkModule::onMsgReceived(const ModuleMessage &msg)
+void MavlinkModule::onMsgReceived(const Message &msg)
 {
     msgArrived++;
-    getCore()->getModuleMessagesBroker()->publish(msg);
+    getCore()->getMessageBroker()->publish(msg);
 }
 
 void MavlinkModule::onStartStreamToggled(bool state)
@@ -126,7 +127,7 @@ void MavlinkModule::onOpenLogFolderClick()
     }
 }
 
-void MavlinkModule::onCommandReceived(const ModuleMessage &msg)
+void MavlinkModule::onCommandReceived(const Message &msg)
 {
     mavlink_message_t encoded_mvl_msg;
     if (!mavlinkCommandAdapter.encodeCommand(msg, encoded_mvl_msg))
@@ -142,20 +143,20 @@ void MavlinkModule::onCommandReceived(const ModuleMessage &msg)
     {
         mavlinkCommandAdapter.send(encoded_mvl_msg);
 
-        ModuleMessage confirmationMsg(
+        Message confirmationMsg(
             Topic((QString)SkywardHubStrings::logCommandsTopic));
 
-        auto nameField = MessageField(msg.getTopic().toString().replace(
+        auto nameField = Field(msg.getTopic().toString().replace(
             SkywardHubStrings::commandsTopic + "/", ""));
         confirmationMsg.setField("name", nameField);
 
-        auto idField = MessageField((uint64_t)encoded_mvl_msg.msgid);
+        auto idField = Field((uint64_t)encoded_mvl_msg.msgid);
         confirmationMsg.setField("message_id", idField);
 
-        auto seqField = MessageField((uint64_t)encoded_mvl_msg.seq);
+        auto seqField = Field((uint64_t)encoded_mvl_msg.seq);
         confirmationMsg.setField("sequence_number", seqField);
 
-        getCore()->getModuleMessagesBroker()->publish(confirmationMsg);
+        getCore()->getMessageBroker()->publish(confirmationMsg);
     }
 }
 
diff --git a/src/shared/Modules/Mavlink/MavlinkModule.h b/src/shared/Modules/Mavlink/MavlinkModule.h
index 2243200e52fb59fc5917c9f5e832d5b45de3a31e..5aa65b90f830e52a77555602ec2f72365f72d5c5 100644
--- a/src/shared/Modules/Mavlink/MavlinkModule.h
+++ b/src/shared/Modules/Mavlink/MavlinkModule.h
@@ -1,17 +1,18 @@
 #pragma once
 
+#include <Core/Module/Module.h>
+
 #include <QSerialPort>
 #include <QTimer>
 #include <QWidget>
 
 #include "Components/ToggleButton/ToggleButton.h"
-#include "Core/Message/ModuleMessage.h"
-#include "Core/Module.h"
+#include "Core/Message/Message.h"
 #include "MavlinkCommandAdapter.h"
 #include "MavlinkReader.h"
 #include "Modules/DefaultModule/DefaultModule.h"
 
-Q_DECLARE_METATYPE(ModuleMessage);
+Q_DECLARE_METATYPE(Message);
 
 namespace Ui
 {
@@ -30,12 +31,12 @@ public:
     XmlObject toXmlObject() override;
     void fromXmlObject(const XmlObject &xmlObject) override;
 
-    void onCommandReceived(const ModuleMessage &msg);
+    void onCommandReceived(const Message &msg);
 
 public slots:
     void onStartClicked();
     void onStopClicked();
-    void onMsgReceived(const ModuleMessage &msg);
+    void onMsgReceived(const Message &msg);
     void onLinkQualityTimerTick();
 
 protected:
diff --git a/src/shared/Modules/Mavlink/MavlinkReader.cpp b/src/shared/Modules/Mavlink/MavlinkReader.cpp
index 560bc0561b2f520a68e9d9706680af188f52eb17..cac961ce0d31b0274cc1825ee95f75c17312bb2b 100644
--- a/src/shared/Modules/Mavlink/MavlinkReader.cpp
+++ b/src/shared/Modules/Mavlink/MavlinkReader.cpp
@@ -46,7 +46,7 @@ void MavlinkReader::onReadyRead()
     for (auto it = bytes.begin(); it != bytes.end(); ++it)
         if (mavlink_parse_char(MAVLINK_COMM_0, *it, &decodedMessage,
                                &mavlinkStatus))
-            emit msgReceived(generateModuleMessage(decodedMessage));
+            emit msgReceived(generateMessage(decodedMessage));
 
     if (logFile.isOpen())
         logFile.write(bytes.constData(), sizeof(char) * bytes.length());
@@ -54,15 +54,15 @@ void MavlinkReader::onReadyRead()
 
 void MavlinkReader::setSerialPort(QSerialPort* port) { serialPort = port; }
 
-ModuleMessage MavlinkReader::generateModuleMessage(const mavlink_message_t& msg)
+Message MavlinkReader::generateMessage(const mavlink_message_t& msg)
 {
     const mavlink_message_info_t& info = getMessageFormat(msg.msgid);
 
-    QMap<QString, MessageField> fields;
+    QMap<QString, Field> fields;
     for (unsigned i = 0; i < info.num_fields; i++)
         fields[QString(info.fields[i].name)] = decodeField(msg, info.fields[i]);
 
-    ModuleMessage output;
+    Message output;
     output.setTopic(
         Topic(SkywardHubStrings::mavlink_received_msg_topic + "/" + info.name));
     output.setFields(std::move(fields));
@@ -125,8 +125,8 @@ void MavlinkReader::setLogFilePath()
     logFilePath = proposedFilePath + fileNumber + extension;
 }
 
-MessageField MavlinkReader::decodeField(const mavlink_message_t& msg,
-                                        const mavlink_field_info_t& field)
+Field MavlinkReader::decodeField(const mavlink_message_t& msg,
+                                 const mavlink_field_info_t& field)
 {
     if (field.array_length == 0)
     {
@@ -146,85 +146,80 @@ MessageField MavlinkReader::decodeField(const mavlink_message_t& msg,
                     break;
             }
 
-            return MessageField(str);
+            return Field(str);
         }
         else
         {
-            QList<MessageField> array;
-            array.reserve(field.array_length);
-            for (unsigned i = 0; i < field.array_length; i++)
-            {
-                array.append(decodeArrayElement(msg, field, i));
-            }
-            return MessageField(std::move(array));
+            return Field();
         }
     }
 }
 
-MessageField MavlinkReader::decodeArrayElement(
-    const mavlink_message_t& msg, const mavlink_field_info_t& field, int idx)
+Field MavlinkReader::decodeArrayElement(const mavlink_message_t& msg,
+                                        const mavlink_field_info_t& field,
+                                        int idx)
 {
     switch (field.type)
     {
         case MAVLINK_TYPE_CHAR:
         {
-            return MessageField(
-                _MAV_RETURN_char(&msg, field.wire_offset + idx * 1));
+            return Field(static_cast<uint64_t>(
+                _MAV_RETURN_char(&msg, field.wire_offset + idx * 1)));
         }
         case MAVLINK_TYPE_UINT8_T:
         {
-            return MessageField(static_cast<uint64_t>(
+            return Field(static_cast<uint64_t>(
                 _MAV_RETURN_uint8_t(&msg, field.wire_offset + idx * 1)));
         }
         case MAVLINK_TYPE_INT8_T:
         {
-            return MessageField(static_cast<int64_t>(
+            return Field(static_cast<int64_t>(
                 _MAV_RETURN_int8_t(&msg, field.wire_offset + idx * 1)));
         }
         case MAVLINK_TYPE_UINT16_T:
         {
-            return MessageField(static_cast<uint64_t>(
+            return Field(static_cast<uint64_t>(
                 _MAV_RETURN_uint16_t(&msg, field.wire_offset + idx * 2)));
         }
         case MAVLINK_TYPE_INT16_T:
         {
-            return MessageField(static_cast<int64_t>(
+            return Field(static_cast<int64_t>(
                 _MAV_RETURN_int16_t(&msg, field.wire_offset + idx * 2)));
         }
         case MAVLINK_TYPE_UINT32_T:
         {
-            return MessageField(static_cast<uint64_t>(
+            return Field(static_cast<uint64_t>(
                 _MAV_RETURN_uint32_t(&msg, field.wire_offset + idx * 4)));
         }
         case MAVLINK_TYPE_INT32_T:
         {
-            return MessageField(static_cast<int64_t>(
+            return Field(static_cast<int64_t>(
                 _MAV_RETURN_int32_t(&msg, field.wire_offset + idx * 4)));
         }
         case MAVLINK_TYPE_UINT64_T:
         {
-            return MessageField(static_cast<uint64_t>(
+            return Field(static_cast<uint64_t>(
                 _MAV_RETURN_uint64_t(&msg, field.wire_offset + idx * 8)));
         }
         case MAVLINK_TYPE_INT64_T:
         {
-            return MessageField(static_cast<int64_t>(
+            return Field(static_cast<int64_t>(
                 _MAV_RETURN_int64_t(&msg, field.wire_offset + idx * 8)));
         }
         case MAVLINK_TYPE_FLOAT:
         {
-            return MessageField(static_cast<double>(
+            return Field(static_cast<double>(
                 _MAV_RETURN_float(&msg, field.wire_offset + idx * 4)));
         }
         case MAVLINK_TYPE_DOUBLE:
         {
-            return MessageField(static_cast<double>(
+            return Field(static_cast<double>(
                 _MAV_RETURN_double(&msg, field.wire_offset + idx * 8)));
         }
         default:
         {
             // Unsupported: return EMPTY
-            return MessageField();
+            return Field();
         }
     }
 }
diff --git a/src/shared/Modules/Mavlink/MavlinkReader.h b/src/shared/Modules/Mavlink/MavlinkReader.h
index 22d29830fed7ca2700b8cef9733ed8a7e9846995..c31ed787d55518ccc9f826984549b68b84a46257 100644
--- a/src/shared/Modules/Mavlink/MavlinkReader.h
+++ b/src/shared/Modules/Mavlink/MavlinkReader.h
@@ -4,7 +4,7 @@
 #include <QFile>
 #include <QSerialPort>
 
-#include "Core/Message/ModuleMessage.h"
+#include "Core/Message/Message.h"
 #include "Core/XmlObject.h"
 #include "MavlinkVersionHeader.h"
 
@@ -20,7 +20,7 @@ public:
     void startReading();
     void stopReading();
 
-    ModuleMessage generateModuleMessage(const mavlink_message_t& msg);
+    Message generateMessage(const mavlink_message_t& msg);
 
     void setSerialPort(QSerialPort* port);
     void closeLog();
@@ -29,19 +29,19 @@ public:
     static const mavlink_message_info_t& getMessageFormat(uint8_t messageId);
 
 signals:
-    void msgReceived(const ModuleMessage& msg);
+    void msgReceived(const Message& msg);
 
 private slots:
     void onReadyRead();
 
 protected:
     /* convert a field of any type to a string */
-    MessageField decodeField(const mavlink_message_t& msg,
-                             const mavlink_field_info_t& field);
+    Field decodeField(const mavlink_message_t& msg,
+                      const mavlink_field_info_t& field);
 
     /* if field is an array, decode every element in the array */
-    MessageField decodeArrayElement(const mavlink_message_t& msg,
-                                    const mavlink_field_info_t& field, int idx);
+    Field decodeArrayElement(const mavlink_message_t& msg,
+                             const mavlink_field_info_t& field, int idx);
 
     void setLogFilePath();
 
diff --git a/src/shared/Modules/Mavlink/MavlinkRocketMsgTestingModule.cpp b/src/shared/Modules/Mavlink/MavlinkRocketMsgTestingModule.cpp
index 83decea70ecafe550659de83e31d23c047739d0b..c9bda55b7ab229aad399031aeb38478b73ba3b5d 100644
--- a/src/shared/Modules/Mavlink/MavlinkRocketMsgTestingModule.cpp
+++ b/src/shared/Modules/Mavlink/MavlinkRocketMsgTestingModule.cpp
@@ -1,6 +1,6 @@
 #include "MavlinkRocketMsgTestingModule.h"
 
-#include <Core/ModuleMessagesBroker.h>
+#include <Core/MessageBroker/MessageBroker.h>
 
 #include <QDebug>
 #include <QMap>
@@ -213,9 +213,9 @@ bool MavlinkRocketMsgTestingModule::testMavlinkEncodeAndDecode(
     if (ok)
     {
         MavlinkReader mavlinkReader(nullptr);
-        ModuleMessage msgProduced = mavlinkReader.generateModuleMessage(mavMsg);
+        Message msgProduced = mavlinkReader.generateMessage(mavMsg);
         Topic currentTopic(getCurrentTopic().trimmed());
-        getCore()->getModuleMessagesBroker()->publish(msgProduced);
+        getCore()->getMessageBroker()->publish(msgProduced);
     }
     return ok;
 }
diff --git a/src/shared/Modules/ModuleInfo.h b/src/shared/Modules/ModuleInfo.h
index e153fc7bde7be01b872e61044abc38777cb1f72c..de76b3e92d2e1df726f478c22cbfc9ffa3e2f3b5 100644
--- a/src/shared/Modules/ModuleInfo.h
+++ b/src/shared/Modules/ModuleInfo.h
@@ -23,7 +23,8 @@ enum ModuleId
     MAVLINK_RCK_TESTING,
     TIMER_CONTROLLER,
     MODULETEST,
-    TABS
+    TABS,
+    FILTER_SELECTOR,
 };
 
 enum ModuleCategory
diff --git a/src/shared/Modules/ModulesList.cpp b/src/shared/Modules/ModulesList.cpp
index 93fd7ef32a3c98c2e223ffef8dff92c7d6c7c1b1..22d1be0818fb55b29b7651e1ca929acbed56eee7 100644
--- a/src/shared/Modules/ModulesList.cpp
+++ b/src/shared/Modules/ModulesList.cpp
@@ -1,5 +1,6 @@
 #include "ModulesList.h"
 
+#include <Components/FilterSelector/FilterSelector.h>
 #include <Components/ModulesPicker/ModulesPicker.h>
 #include <Modules/CommandPad/CommandPad.h>
 #include <Modules/CompactCommandPad/CompactCommandPad.h>
diff --git a/src/shared/Modules/OrientationVisualizer/OrientationVisualizer.cpp b/src/shared/Modules/OrientationVisualizer/OrientationVisualizer.cpp
index 956209a46fcd1e8d221004cd16e224ccb8dc374b..1aea11c59d7dc272371477f8a31ee03800bfd579 100644
--- a/src/shared/Modules/OrientationVisualizer/OrientationVisualizer.cpp
+++ b/src/shared/Modules/OrientationVisualizer/OrientationVisualizer.cpp
@@ -28,14 +28,14 @@ OrientationVisualizer::OrientationVisualizer(QWidget *parent)
 
     updateOrientation(0, 0, 0, 1);
 
-    getCore()->getModuleMessagesBroker()->subscribe(
-        {"Mav/PAYLOAD_FLIGHT_TM"}, this,
-        [this](const ModuleMessage &msg)
+    getCore()->getMessageBroker()->subscribe(
+        Filter::fromString("Mav/PAYLOAD_FLIGHT_TM"), this,
+        [this](const Message &msg)
         {
-            updateOrientation(msg.getField("nas_qx").getDouble(0.0),
-                              msg.getField("nas_qy").getDouble(0.0),
-                              msg.getField("nas_qz").getDouble(0.0),
-                              msg.getField("nas_qw").getDouble(0.0));
+            updateOrientation(msg.getField("nas_qx").getDouble(),
+                              msg.getField("nas_qy").getDouble(),
+                              msg.getField("nas_qz").getDouble(),
+                              msg.getField("nas_qw").getDouble());
         });
 }
 
diff --git a/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.cpp b/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.cpp
index 17a43ea2fde5cd3ef1764f02df62f165ad0fd390..3174a00de00ef409611365cce43ccff45ade744b 100644
--- a/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.cpp
+++ b/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.cpp
@@ -1,8 +1,9 @@
 #include "OutgoingMessagesViewerModule.h"
 
+#include <Core/MessageBroker/MessageBroker.h>
+
 #include <QTableWidgetItem>
 
-#include "Core/ModuleMessagesBroker.h"
 #include "Modules/SkywardHubStrings.h"
 #include "ui_OutgoingMessagesViewerModule.h"
 
@@ -12,16 +13,16 @@ OutgoingMessagesViewerModule::OutgoingMessagesViewerModule(QWidget* parent)
     ui->setupUi(this);
     defaultContextMenuSetup();
 
-    getCore()->getModuleMessagesBroker()->subscribe(
-        {SkywardHubStrings::logCommandsTopic}, this,
-        [this](const ModuleMessage& msg) { addMsgSent(msg); });
+    getCore()->getMessageBroker()->subscribe(
+        Filter::fromString(SkywardHubStrings::logCommandsTopic), this,
+        [this](const Message& msg) { addMsgSent(msg); });
 
-    getCore()->getModuleMessagesBroker()->subscribe(
-        SkywardHubStrings::mavlink_received_msg_ACK_topic, this,
-        [this](const ModuleMessage& msg) { handleAck(msg); });
-    getCore()->getModuleMessagesBroker()->subscribe(
-        SkywardHubStrings::mavlink_received_msg_NACK_topic, this,
-        [this](const ModuleMessage& msg) { handleNack(msg); });
+    getCore()->getMessageBroker()->subscribe(
+        Filter::fromString(SkywardHubStrings::mavlink_received_msg_ACK_topic),
+        this, [this](const Message& msg) { handleAck(msg); });
+    getCore()->getMessageBroker()->subscribe(
+        Filter::fromString(SkywardHubStrings::mavlink_received_msg_NACK_topic),
+        this, [this](const Message& msg) { handleNack(msg); });
 }
 
 OutgoingMessagesViewerModule::~OutgoingMessagesViewerModule() { delete ui; }
@@ -38,7 +39,7 @@ void OutgoingMessagesViewerModule::fromXmlObject(const XmlObject& xmlObject)
     Q_UNUSED(xmlObject);
 }
 
-void OutgoingMessagesViewerModule::addMsgSent(const ModuleMessage& msg)
+void OutgoingMessagesViewerModule::addMsgSent(const Message& msg)
 {
     int row    = updateVerticalHeaders(msg);
     int column = 0;
@@ -51,16 +52,16 @@ void OutgoingMessagesViewerModule::addMsgSent(const ModuleMessage& msg)
     registerMessage(newItem, msg);
 }
 
-QString OutgoingMessagesViewerModule::computeMsgName(const ModuleMessage& msg)
+QString OutgoingMessagesViewerModule::computeMsgName(const Message& msg)
 {
     return msg.getField("name").getString();
 }
 
-void OutgoingMessagesViewerModule::handleAck(const ModuleMessage& ack)
+void OutgoingMessagesViewerModule::handleAck(const Message& ack)
 {
     for (int i = 0; i < messages.count(); i++)
     {
-        ModuleMessage msg = messages[i].getMsg();
+        Message msg = messages[i].getMsg();
 
         // Color the message the ack is for by checking the message is and
         // sequence number
@@ -70,11 +71,11 @@ void OutgoingMessagesViewerModule::handleAck(const ModuleMessage& ack)
     }
 }
 
-void OutgoingMessagesViewerModule::handleNack(const ModuleMessage& nack)
+void OutgoingMessagesViewerModule::handleNack(const Message& nack)
 {
     for (int i = 0; i < messages.count(); i++)
     {
-        ModuleMessage msg = messages[i].getMsg();
+        Message msg = messages[i].getMsg();
 
         // Color the message the nack is for by checking the message is and
         // sequence number
@@ -84,12 +85,11 @@ void OutgoingMessagesViewerModule::handleNack(const ModuleMessage& nack)
     }
 }
 
-int OutgoingMessagesViewerModule::updateVerticalHeaders(
-    const ModuleMessage& msg)
+int OutgoingMessagesViewerModule::updateVerticalHeaders(const Message& msg)
 {
     int row = 0;  // Insert on top
     QTime time(0, 0, 0, 0);
-    time = time.addMSecs(msg.getField("timestamp").getInteger(0));
+    time = time.addMSecs(msg.getField("timestamp").getInteger());
 
     QString headerTxt = time.toString("hh.mm.ss (zzz)");
     ui->tableWidget->insertRow(row);
@@ -106,7 +106,7 @@ int OutgoingMessagesViewerModule::updateVerticalHeaders(
 }
 
 void OutgoingMessagesViewerModule::registerMessage(QTableWidgetItem* item,
-                                                   const ModuleMessage& msg)
+                                                   const Message& msg)
 {
     messages.prepend(MessageLog(item, msg));
     if (messages.count() > maxSize)
@@ -117,7 +117,7 @@ void OutgoingMessagesViewerModule::registerMessage(QTableWidgetItem* item,
 
 // ____________________ MESSAGE LOG CLASS _______________________________
 
-MessageLog::MessageLog(QTableWidgetItem* item, const ModuleMessage& msg)
+MessageLog::MessageLog(QTableWidgetItem* item, const Message& msg)
 {
     setItem(item);
     setMsg(msg);
@@ -127,6 +127,6 @@ QTableWidgetItem* MessageLog::getItem() const { return item; }
 
 void MessageLog::setItem(QTableWidgetItem* value) { item = value; }
 
-ModuleMessage MessageLog::getMsg() const { return msg; }
+Message MessageLog::getMsg() const { return msg; }
 
-void MessageLog::setMsg(const ModuleMessage& value) { msg = value; }
+void MessageLog::setMsg(const Message& value) { msg = value; }
diff --git a/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.h b/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.h
index 48204d3c16bd2cc96fcc34bb15fc1843fb0eb01a..a8d1eac727072b422d7af65a5313f301c64edb53 100644
--- a/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.h
+++ b/src/shared/Modules/OutgoingMessagesViewer/OutgoingMessagesViewerModule.h
@@ -1,10 +1,10 @@
 #pragma once
 
-#include <QWidget>
+#include <Core/Message/Message.h>
+#include <Core/Module/Module.h>
+#include <Modules/DefaultModule/DefaultModule.h>
 
-#include "Core/Message/ModuleMessage.h"
-#include "Core/Module.h"
-#include "Modules/DefaultModule/DefaultModule.h"
+#include <QWidget>
 
 class QTableWidgetItem;
 
@@ -12,17 +12,17 @@ class MessageLog
 {
 
 public:
-    explicit MessageLog(QTableWidgetItem* item, const ModuleMessage& msg);
+    explicit MessageLog(QTableWidgetItem* item, const Message& msg);
 
     QTableWidgetItem* getItem() const;
     void setItem(QTableWidgetItem* value);
 
-    ModuleMessage getMsg() const;
-    void setMsg(const ModuleMessage& value);
+    Message getMsg() const;
+    void setMsg(const Message& value);
 
 private:
     QTableWidgetItem* item = nullptr;
-    ModuleMessage msg;
+    Message msg;
 };
 
 namespace Ui
@@ -43,14 +43,14 @@ public:
     XmlObject toXmlObject() override;
     void fromXmlObject(const XmlObject& xmlObject) override;
 
-    void addMsgSent(const ModuleMessage& msg);
-    void handleAck(const ModuleMessage& ack);
-    void handleNack(const ModuleMessage& nack);
+    void addMsgSent(const Message& msg);
+    void handleAck(const Message& ack);
+    void handleNack(const Message& nack);
 
 protected:
-    int updateVerticalHeaders(const ModuleMessage& msg);
-    void registerMessage(QTableWidgetItem* item, const ModuleMessage& msg);
-    QString computeMsgName(const ModuleMessage& msg);
+    int updateVerticalHeaders(const Message& msg);
+    void registerMessage(QTableWidgetItem* item, const Message& msg);
+    QString computeMsgName(const Message& msg);
 
 private:
     Ui::OutgoingMessagesViewerModule* ui;
diff --git a/src/shared/Modules/SkywardHub/DeployerPathPicker.cpp b/src/shared/Modules/SkywardHub/DeployerPathPicker.cpp
index 69531a0c7e82d4f0ffe83eaace5d8421e8e392eb..f7142b67f2c8f33a1eac82695ed19c1903c4aff1 100644
--- a/src/shared/Modules/SkywardHub/DeployerPathPicker.cpp
+++ b/src/shared/Modules/SkywardHub/DeployerPathPicker.cpp
@@ -8,7 +8,7 @@ DeployerPathPicker::DeployerPathPicker(QWidget *parent)
     : QDialog(parent), ui(new Ui::DeployerPathPicker)
 {
     ui->setupUi(this);
-    // this->setAttribute(Qt::WA_DeleteOnClose, true); // WA_DeleteOnClose is
+    // setAttribute(Qt::WA_DeleteOnClose, true); // WA_DeleteOnClose is
     // set to true, so this widget will be deleted on close
 
     connect(ui->pushButton_selectDeployFolder, &QPushButton::clicked, this,
diff --git a/src/shared/Modules/SkywardHub/SkywardHubModule.cpp b/src/shared/Modules/SkywardHub/SkywardHubModule.cpp
index e46b4b504f86439739496975400ae55bcde7d2d8..a47a10337b82a99060dd80615947589f127b2d72 100644
--- a/src/shared/Modules/SkywardHub/SkywardHubModule.cpp
+++ b/src/shared/Modules/SkywardHub/SkywardHubModule.cpp
@@ -1,11 +1,12 @@
 #include "SkywardHubModule.h"
 
+#include <Core/ModulesManager/ModulesManager.h>
+
 #include <QDir>
 #include <QGridLayout>
 #include <QLabel>
 #include <QPushButton>
 
-#include "Core/ModulesManager.h"
 #include "Deployer.h"
 #include "Modules/MainWindow/SkywardHubMainWindow.h"
 #include "Modules/SkywardHubStrings.h"
diff --git a/src/shared/Modules/Splitter/Splitter.cpp b/src/shared/Modules/Splitter/Splitter.cpp
index dc08eb7657968addeecb68674fb880ef5899a933..8dc76af88c31c0734dc7fee895a89f04ebca6e2b 100644
--- a/src/shared/Modules/Splitter/Splitter.cpp
+++ b/src/shared/Modules/Splitter/Splitter.cpp
@@ -1,7 +1,7 @@
 #include "Splitter.h"
 
 #include <Components/ContextMenuSeparator/ContextMenuSeparator.h>
-#include <Core/ModulesManager.h>
+#include <Core/ModulesManager/ModulesManager.h>
 
 #include <QDebug>
 #include <QLabel>
@@ -85,10 +85,9 @@ void Splitter::addModule(Module* module)
 
 void Splitter::addModule(Module* module, int position)
 {
-    connect(module->getModuleEventsHandler(),
-            &ModuleEventsHandler::replaceMeWith, this, &Splitter::replace);
-    connect(module->getModuleEventsHandler(),
-            &ModuleEventsHandler::contextMenuRequest, this,
+    connect(module->getEventHandler(), &EventHandler::replaceMeWith, this,
+            &Splitter::replace);
+    connect(module->getEventHandler(), &EventHandler::contextMenuRequest, this,
             &Splitter::onSkywardHubContextMenuRequested);
 
     if (position < splitter->count())
diff --git a/src/shared/Modules/Splitter/Splitter.h b/src/shared/Modules/Splitter/Splitter.h
index f7a1f6bd68fb40b1355a0536c6ef9c4a8f84f039..906f7efb38188649df7c441ac3d68c63af7754d1 100644
--- a/src/shared/Modules/Splitter/Splitter.h
+++ b/src/shared/Modules/Splitter/Splitter.h
@@ -1,11 +1,11 @@
 #pragma once
 
+#include <Core/Module/Module.h>
+#include <Modules/DefaultModule/DefaultModule.h>
+
 #include <QSplitter>
 #include <QWidget>
 
-#include "Core/Module.h"
-#include "Modules/DefaultModule/DefaultModule.h"
-
 class Splitter : public DefaultModule
 {
     Q_OBJECT
diff --git a/src/shared/Modules/StateViewer/StateViewer.cpp b/src/shared/Modules/StateViewer/StateViewer.cpp
index f80aaa5a26e965ea0a67e959456ce643292f7a5c..f1f2cb2567db24133353b56acf64c4af07462224 100644
--- a/src/shared/Modules/StateViewer/StateViewer.cpp
+++ b/src/shared/Modules/StateViewer/StateViewer.cpp
@@ -1,7 +1,7 @@
 #include "StateViewer.h"
 
-#include <Components/TopicAndFieldFilterSelector/TopicAndFieldFilterSelector.h>
-#include <Core/ModuleMessagesBroker.h>
+#include <Components/FilterSelector/FilterSelector.h>
+#include <Core/MessageBroker/MessageBroker.h>
 
 StateViewerModule::StateViewerModule(QWidget* parent) : DefaultModule(parent)
 {
@@ -11,8 +11,7 @@ StateViewerModule::StateViewerModule(QWidget* parent) : DefaultModule(parent)
 
 StateViewerModule::~StateViewerModule()
 {
-    getCore()->getModuleMessagesBroker()->unsubscribe(filter.getTopicFilter(),
-                                                      this);
+    getCore()->getMessageBroker()->unsubscribe(filter, this);
 }
 
 QWidget* StateViewerModule::toWidget() { return this; }
@@ -30,8 +29,7 @@ void StateViewerModule::fromXmlObject(const XmlObject& xmlObject)
 {
     if (xmlObject.getObjectName() == getName(ModuleId::STATEVIEWER))
     {
-        auto filter = TopicAndFieldFilter::fromStringUnsafe(
-            xmlObject.getAttribute("filter"));
+        auto filter = Filter::fromString(xmlObject.getAttribute("filter"));
         setFilter(filter);
     }
 }
@@ -65,31 +63,28 @@ void StateViewerModule::addCustomActionsToMenu()
 
 void StateViewerModule::onConfigureClicked()
 {
-    TopicAndFieldFilterSelector::selectFilter(
-        filter,
-        [this](const TopicAndFieldFilter& newFilter) { setFilter(newFilter); });
+    FilterSelector::selectFilter(
+        filter, [this](const Filter& newFilter) { setFilter(newFilter); });
 }
 
-void StateViewerModule::setFilter(const TopicAndFieldFilter& newFilter)
+void StateViewerModule::setFilter(const Filter& newFilter)
 {
-    getCore()->getModuleMessagesBroker()->unsubscribe(filter.getTopicFilter(),
-                                                      this);
-    getCore()->getModuleMessagesBroker()->subscribe(
-        newFilter.getTopicFilter(), this,
-        [this](const ModuleMessage& msg) { onMsgReceived(msg); });
+    getCore()->getMessageBroker()->unsubscribe(filter, this);
+    getCore()->getMessageBroker()->subscribe(
+        newFilter, this, [this](const Message& msg) { onMsgReceived(msg); });
     filter = newFilter;
 }
 
-void StateViewerModule::onMsgReceived(const ModuleMessage& msg)
+void StateViewerModule::onMsgReceived(const Message& msg)
 {
-    MessageField field;
+    Field field;
 
     // Check if the message matches the filter
-    if (!filter.matchMessage(msg, field))
+    if (!filter.match(msg))
         return;
 
     StatesList::State state =
-        static_cast<StatesList::State>(field.getUInteger(-1));
+        static_cast<StatesList::State>(field.getUnsignedInteger());
 
     if (state == StatesList::State::INVALID)
         return;
diff --git a/src/shared/Modules/StateViewer/StateViewer.h b/src/shared/Modules/StateViewer/StateViewer.h
index 194d574ae0526d39e90f558a9b865bffe8029aa1..100309ccd5029b60938ace4f3e7124518051c48a 100644
--- a/src/shared/Modules/StateViewer/StateViewer.h
+++ b/src/shared/Modules/StateViewer/StateViewer.h
@@ -1,7 +1,7 @@
 #pragma once
 
-#include <Core/Message/ModuleMessage.h>
-#include <Core/Message/TopicAndFieldFilter.h>
+#include <Core/Message/Filter.h>
+#include <Core/Message/Message.h>
 #include <Modules/DefaultModule/DefaultModule.h>
 
 #include <QLabel>
@@ -26,11 +26,11 @@ private:
     void setupUi();
     void addCustomActionsToMenu() override;
     void onConfigureClicked();
-    void setFilter(const TopicAndFieldFilter& filter);
-    void onMsgReceived(const ModuleMessage& msg);
+    void setFilter(const Filter& filter);
+    void onMsgReceived(const Message& msg);
 
     QHBoxLayout* outerLayout;
 
-    TopicAndFieldFilter filter;
+    Filter filter;
     StatesList::State currentState;
 };
diff --git a/src/shared/Modules/Tabs/TabsModule.cpp b/src/shared/Modules/Tabs/TabsModule.cpp
index c3092fc97af019c2247b15e54b9b31fe52bbcff9..1c8b3ed7824518a51295f20d3abfea658390bfaa 100644
--- a/src/shared/Modules/Tabs/TabsModule.cpp
+++ b/src/shared/Modules/Tabs/TabsModule.cpp
@@ -1,11 +1,11 @@
 #include "TabsModule.h"
 
+#include <Core/ModulesManager/ModulesManager.h>
+
 #include <QBoxLayout>
 #include <QDebug>
 #include <QLabel>
 
-#include "Core/ModulesManager.h"
-
 TabsModule::TabsModule(QWidget* parent) : DefaultModule{parent}
 {
     setupUi();
@@ -92,14 +92,11 @@ void TabsModule::fromXmlObject(const XmlObject& xmlObject)
 
 void TabsModule::addTab(const QString& tabName, Module* module)
 {
-    connect(module->getModuleEventsHandler(),
-            &ModuleEventsHandler::replaceMeWith, this,
+    connect(module->getEventHandler(), &EventHandler::replaceMeWith, this,
             &TabsModule::replaceTabContent);
-    connect(module->getModuleEventsHandler(),
-            &ModuleEventsHandler::contextMenuRequest, this,
+    connect(module->getEventHandler(), &EventHandler::contextMenuRequest, this,
             &TabsModule::onSkywardHubContextMenuRequested);
-    connect(module->getModuleEventsHandler(),
-            &ModuleEventsHandler::beforeDelete, this,
+    connect(module->getEventHandler(), &EventHandler::beforeDelete, this,
             &TabsModule::onTabDeleted);
 
     auto* listItem = new QListWidgetItem();
@@ -135,13 +132,12 @@ void TabsModule::replaceTabContent(Module* from, Module* to)
     tabContents->setCurrentWidget(to->toWidget());
 
     // Connect the module to the slots
-    connect(to->getModuleEventsHandler(), &ModuleEventsHandler::replaceMeWith,
-            this, &TabsModule::replaceTabContent);
-    connect(to->getModuleEventsHandler(),
-            &ModuleEventsHandler::contextMenuRequest, this,
+    connect(to->getEventHandler(), &EventHandler::replaceMeWith, this,
+            &TabsModule::replaceTabContent);
+    connect(to->getEventHandler(), &EventHandler::contextMenuRequest, this,
             &TabsModule::onSkywardHubContextMenuRequested);
-    connect(to->getModuleEventsHandler(), &ModuleEventsHandler::beforeDelete,
-            this, &TabsModule::onTabDeleted);
+    connect(to->getEventHandler(), &EventHandler::beforeDelete, this,
+            &TabsModule::onTabDeleted);
 
     // forces UI update
     tabContents->update();
@@ -162,7 +158,7 @@ void TabsModule::onTabDeleted(Module* module)
 
     if (contentModules.isEmpty())
     {
-        emit getModuleEventsHandler()->replaceMeWith(
+        emit getEventHandler()->replaceMeWith(
             this, getCore()->getModulesManager()->instantiateDefaultModule());
         this->deleteLater();
     }
diff --git a/src/shared/Modules/Test/TestModule.cpp b/src/shared/Modules/Test/TestModule.cpp
index b9eec753313a1f5763845139458be0abb5b5e90e..6e78e8e92990d731c0f9eb0a96fd41436bd034f7 100644
--- a/src/shared/Modules/Test/TestModule.cpp
+++ b/src/shared/Modules/Test/TestModule.cpp
@@ -1,8 +1,9 @@
 #include "TestModule.h"
 
+#include <Core/MessageBroker/MessageBroker.h>
+#include <Core/ModulesManager/ModulesManager.h>
+
 #include "Components/ContextMenuSeparator/ContextMenuSeparator.h"
-#include "Core/ModuleMessagesBroker.h"
-#include "Core/ModulesManager.h"
 #include "ui_TestModule.h"
 
 TestModule::TestModule(QWidget* parent)
@@ -34,20 +35,20 @@ void TestModule::on_publish_button_clicked()
 {
     QString topic   = ui->topic_lineEdit->text().trimmed();
     QString payload = ui->payload_lineEdit->text().trimmed();
-    ModuleMessage msg(Topic{topic});
-    auto valueField = MessageField(payload);
+    Message msg(Topic{topic});
+    auto valueField = Field(payload);
     msg.setField("value", valueField);
     auto timestampField =
-        MessageField((uint64_t)QTime::currentTime().msecsSinceStartOfDay());
+        Field((uint64_t)QTime::currentTime().msecsSinceStartOfDay());
     msg.setField("timestamp", timestampField);
-    getCore()->getModuleMessagesBroker()->publish(msg);
+    getCore()->getMessageBroker()->publish(msg);
 }
 
 void TestModule::on_subscribe_button_clicked()
 {
-    getCore()->getModuleMessagesBroker()->subscribe(
-        ui->subscribe_lineEdit->text().trimmed(), this,
-        [this](const ModuleMessage& msg)
+    getCore()->getMessageBroker()->subscribe(
+        Filter::fromString(ui->subscribe_lineEdit->text().trimmed()), this,
+        [this](const Message& msg)
         {
             QString oldText = ui->textArea->toPlainText();
             QString line =
@@ -60,8 +61,8 @@ void TestModule::on_subscribe_button_clicked()
 
 void TestModule::on_unsubscribe_button_clicked()
 {
-    getCore()->getModuleMessagesBroker()->unsubscribe(
-        ui->subscribe_lineEdit->text().trimmed(), this);
+    getCore()->getMessageBroker()->unsubscribe(
+        Filter::fromString(ui->subscribe_lineEdit->text().trimmed()), this);
 }
 
 void TestModule::onMaxCharChanged(int value) { maxChar = value; }
diff --git a/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.cpp b/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.cpp
index 297de750326490d41cdf31b7c6fa386c38fd3d07..1109c5a8ad959e7d87d31daaa1ffb50fe56b6076 100644
--- a/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.cpp
+++ b/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.cpp
@@ -1,7 +1,8 @@
 #include "ValuesConverterViewerModule.h"
 
-#include "Core/Message/TopicAndFieldFilter.h"
-#include "Core/ModuleMessagesBroker.h"
+#include <Core/MessageBroker/MessageBroker.h>
+
+#include "Core/Message/Filter.h"
 #include "ValuesViewerConfigPanel.h"
 #include "ui_ValuesConverterViewerModule.h"
 
@@ -11,14 +12,15 @@ ValuesConverterViewerModule::ValuesConverterViewerModule(QWidget* parent)
     ui->setupUi(this);
     defaultContextMenuSetup();
 
-    getCore()->getModuleMessagesBroker()->subscribe(
-        {"*"}, this, [this](const ModuleMessage& msg) { onMsgReceived(msg); });
+    getCore()->getMessageBroker()->subscribe(Filter::fromString("*"), this,
+                                             [this](const Message& msg)
+                                             { onMsgReceived(msg); });
 }
 
 ValuesConverterViewerModule::~ValuesConverterViewerModule()
 {
     clearLabels();
-    getCore()->getModuleMessagesBroker()->unsubscribe({"*"}, this);
+    getCore()->getMessageBroker()->unsubscribe(Filter::fromString("*"), this);
     delete ui;
 }
 
@@ -158,40 +160,40 @@ void ValuesConverterViewerModule::setRules(const QList<ValueElement>& rList)
     }
 }
 
-void ValuesConverterViewerModule::onMsgReceived(const ModuleMessage& msg)
+void ValuesConverterViewerModule::onMsgReceived(const Message& msg)
 {
-    MessageField value;
+    Field value;
 
     for (int i = 0; i < rules.count(); i++)
     {
-        if (TopicAndFieldFilter::fromStringUnsafe(rules[i].getTopic())
-                .matchMessage(msg, value))
-        {
-            if (rules[i].updateCurrentValue(value.getString()))
-            {
-                QTime time(0, 0, 0, 0);
-                uint64_t ms = msg.getField("timestamp").getUInteger(0);
-                time        = time.addMSecs(ms);
-
-                QString str = "(" + time.toString("HH:mm:ss") + ")\n";
-                labels[i]->setText(rules[i].getName() + "\n" + str +
-                                   rules[i].getCurrentValue());
-                if (rules[i].getColor() != "")
-                {
-                    labels[i]->setStyleSheet("color:" + rules[i].getColor() +
-                                             ";");
-                }
-
-                if (rules[i].isEmitActive())
-                {
-                    ModuleMessage convertedMsg(msg);
-                    auto valueField = MessageField(rules[i].getCurrentValue());
-                    convertedMsg.setField("value", valueField);
-                    convertedMsg.setTopic(Topic(rules[i].getOutputTopic()));
-                    getCore()->getModuleMessagesBroker()->publish(convertedMsg);
-                }
-            }
-        }
+        // TODO
+        // if (Filter::fromString(rules[i].getTopic()).matchMessage(msg, value))
+        // {
+        //     if (rules[i].updateCurrentValue(value.getString()))
+        //     {
+        //         QTime time(0, 0, 0, 0);
+        //         uint64_t ms = msg.getField("timestamp").getUnsignedInteger();
+        //         time        = time.addMSecs(ms);
+
+        //         QString str = "(" + time.toString("HH:mm:ss") + ")\n";
+        //         labels[i]->setText(rules[i].getName() + "\n" + str +
+        //                            rules[i].getCurrentValue());
+        //         if (rules[i].getColor() != "")
+        //         {
+        //             labels[i]->setStyleSheet("color:" + rules[i].getColor() +
+        //                                      ";");
+        //         }
+
+        //         if (rules[i].isEmitActive())
+        //         {
+        //             Message convertedMsg(msg);
+        //             auto valueField = Field(rules[i].getCurrentValue());
+        //             convertedMsg.setField("value", valueField);
+        //             convertedMsg.setTopic(Topic(rules[i].getOutputTopic()));
+        //             getCore()->getMessageBroker()->publish(convertedMsg);
+        //         }
+        //     }
+        // }
     }
 }
 
@@ -201,8 +203,8 @@ void ValuesConverterViewerModule::clearRules()
     {
         if (rules[i].getTopic() != "")
         {
-            getCore()->getModuleMessagesBroker()->unsubscribe(
-                rules[i].getTopic(), this);
+            getCore()->getMessageBroker()->unsubscribe(
+                Filter::fromString(rules[i].getTopic()), this);
         }
     }
     rules.clear();
diff --git a/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.h b/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.h
index 432928f036cdb84bb2adfdb8cb53aba1489ecb21..cedad9075767dbbab1476df69cdde3efc362db54 100644
--- a/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.h
+++ b/src/shared/Modules/ValuesConverterViewer/ValuesConverterViewerModule.h
@@ -3,7 +3,7 @@
 #include <QLabel>
 #include <QWidget>
 
-#include "Core/Message/ModuleMessage.h"
+#include "Core/Message/Message.h"
 #include "Modules/DefaultModule/DefaultModule.h"
 #include "ValueElement.h"
 
@@ -36,7 +36,7 @@ protected:
     void createLabels();
     void addRule(const ValueElement& el);
     void setRules(const QList<ValueElement>& rList);
-    void onMsgReceived(const ModuleMessage& msg);
+    void onMsgReceived(const Message& msg);
     void clearRules();
     int findLabelIndexByName(const QString& name);
     bool isTopicPresent(const QString& topic);
diff --git a/src/shared/Modules/ValuesConverterViewer/ValuesViewerConfigPanel.cpp b/src/shared/Modules/ValuesConverterViewer/ValuesViewerConfigPanel.cpp
index 5a014a4b4b443d313e5f8fdc3242ac11fbfde4ad..5f2070cf613350b537ba9cb6067f5b82e79935e3 100644
--- a/src/shared/Modules/ValuesConverterViewer/ValuesViewerConfigPanel.cpp
+++ b/src/shared/Modules/ValuesConverterViewer/ValuesViewerConfigPanel.cpp
@@ -21,7 +21,7 @@ ValuesViewerConfigPanel::ValuesViewerConfigPanel(QWidget* parent)
             &ValuesViewerConfigPanel::onSaveClicked);
     connect(ui->emit_radioButton, &QRadioButton::toggled, this,
             &ValuesViewerConfigPanel::onEmitRadioButtonToggled);
-    this->setAttribute(Qt::WA_DeleteOnClose, true);
+    setAttribute(Qt::WA_DeleteOnClose, true);
 }
 
 ValuesViewerConfigPanel::~ValuesViewerConfigPanel()