diff --git a/Cargo.lock b/Cargo.lock
index f96365e3b3624dfb05a370c868bc9d74e437134e..7f8b1658a899719344ee0ee3b374b2ec72df2938 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2433,6 +2433,7 @@ dependencies = [
  "base64",
  "chrono",
  "derive_more",
+ "lazy_static",
  "log",
  "mobc-redis",
  "rbatis",
diff --git a/Cargo.toml b/Cargo.toml
index d1d90ddfd6c5935e8d7f13f3e0f704ebd53318b8..3528b0d7bfd26548b58564f3b6a7ced093a09dfe 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,6 +25,7 @@ url = "2.2.2"
 base64 = "^0.13.0"
 simple-logging = { version = "^2.0.2" }
 strfmt = "^0.1.6"
+lazy_static = "1.4.0"
 strum = { version = "0.23", features = ["derive"] }
 rbson = { version = "2.0", optional = true }
 rbatis = { version = "^3.0", default-features = false, features = ["runtime-async-std-rustls", "all-database"], optional = true }
diff --git a/src/errors.rs b/src/errors.rs
index 30a8ef98fb48b1de97940940fa710a0ec7cb1715..585adc00a4f81dfa05f1a6711900a552defde137 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -41,12 +41,14 @@ pub enum RustusError {
     UnknownExtension(String),
 }
 
+/// This conversion allows us to use `RustusError` in the `main` function.
 impl From<RustusError> for Error {
     fn from(err: RustusError) -> Self {
         Error::new(ErrorKind::Other, err)
     }
 }
 
+/// Trait to convert errors to http-responses.
 impl ResponseError for RustusError {
     fn error_response(&self) -> HttpResponse {
         HttpResponseBuilder::new(self.status_code())
diff --git a/src/info_storages/mod.rs b/src/info_storages/mod.rs
index e444828a8c38163bacc7d3a45a76f4caee3d3de2..66338b6b0513696b27dc1f44e9f7bf2ed8e8e7b2 100644
--- a/src/info_storages/mod.rs
+++ b/src/info_storages/mod.rs
@@ -1,86 +1,12 @@
-use std::str::FromStr;
-
-use async_trait::async_trait;
-use derive_more::{Display, From};
-
-pub use file_info::FileInfo;
-
-use crate::errors::RustusResult;
-use crate::RustusConf;
-
-mod file_info;
-
-use strum::{EnumIter, IntoEnumIterator};
+pub mod file_info_storage;
 
 #[cfg(feature = "db_info_storage")]
 pub mod db_info_storage;
-pub mod file_info_storage;
 #[cfg(feature = "redis_info_storage")]
 pub mod redis_info_storage;
 
-#[derive(PartialEq, From, Display, Clone, Debug, EnumIter)]
-pub enum AvailableInfoStores {
-    #[display(fmt = "file_info_storage")]
-    Files,
-    #[cfg(feature = "db_info_storage")]
-    #[display(fmt = "db_info_storage")]
-    DB,
-    #[cfg(feature = "redis_info_storage")]
-    #[display(fmt = "redis_info_storage")]
-    Redis,
-}
-
-impl FromStr for AvailableInfoStores {
-    type Err = String;
-
-    fn from_str(input: &str) -> Result<Self, Self::Err> {
-        let available_stores = AvailableInfoStores::iter()
-            .map(|info_store| format!("\t* {}", info_store.to_string()))
-            .collect::<Vec<String>>()
-            .join("\n");
-        let inp_string = String::from(input);
-        for store in AvailableInfoStores::iter() {
-            if inp_string == store.to_string() {
-                return Ok(store);
-            }
-        }
-        Err(format!(
-            "Unknown info storage type.\n Available storages:\n{}",
-            available_stores
-        ))
-    }
-}
-
-impl AvailableInfoStores {
-    /// Convert `AvailableInfoStores` to the impl `InfoStorage`.
-    ///
-    /// # Params
-    /// `config` - Rustus configuration.
-    ///
-    pub async fn get(
-        &self,
-        config: &RustusConf,
-    ) -> RustusResult<Box<dyn InfoStorage + Sync + Send>> {
-        match self {
-            Self::Files => Ok(Box::new(file_info_storage::FileInfoStorage::new(
-                config.clone(),
-            ))),
-            #[cfg(feature = "db_info_storage")]
-            Self::DB => Ok(Box::new(
-                db_info_storage::DBInfoStorage::new(config.clone()).await?,
-            )),
-            #[cfg(feature = "redis_info_storage")]
-            AvailableInfoStores::Redis => Ok(Box::new(
-                redis_info_storage::RedisStorage::new(config.clone()).await?,
-            )),
-        }
-    }
-}
+pub mod models;
 
-#[async_trait]
-pub trait InfoStorage {
-    async fn prepare(&mut self) -> RustusResult<()>;
-    async fn set_info(&self, file_info: &FileInfo, create: bool) -> RustusResult<()>;
-    async fn get_info(&self, file_id: &str) -> RustusResult<FileInfo>;
-    async fn remove_info(&self, file_id: &str) -> RustusResult<()>;
-}
+pub use models::available_info_storages::AvailableInfoStores;
+pub use models::file_info::FileInfo;
+pub use models::info_store::InfoStorage;
diff --git a/src/info_storages/models/available_info_storages.rs b/src/info_storages/models/available_info_storages.rs
new file mode 100644
index 0000000000000000000000000000000000000000..256fb348be60a57cda95817684511092c5641431
--- /dev/null
+++ b/src/info_storages/models/available_info_storages.rs
@@ -0,0 +1,74 @@
+use std::str::FromStr;
+
+use derive_more::{Display, From};
+
+use crate::errors::RustusResult;
+use crate::RustusConf;
+
+use crate::info_storages::{file_info_storage, InfoStorage};
+use strum::{EnumIter, IntoEnumIterator};
+
+#[cfg(feature = "db_info_storage")]
+use crate::info_storages::db_info_storage;
+
+#[cfg(feature = "redis_info_storage")]
+use crate::info_storages::redis_info_storage;
+
+#[derive(PartialEq, From, Display, Clone, Debug, EnumIter)]
+pub enum AvailableInfoStores {
+    #[display(fmt = "file_info_storage")]
+    Files,
+    #[cfg(feature = "db_info_storage")]
+    #[display(fmt = "db_info_storage")]
+    DB,
+    #[cfg(feature = "redis_info_storage")]
+    #[display(fmt = "redis_info_storage")]
+    Redis,
+}
+
+impl FromStr for AvailableInfoStores {
+    type Err = String;
+
+    fn from_str(input: &str) -> Result<Self, Self::Err> {
+        let available_stores = AvailableInfoStores::iter()
+            .map(|info_store| format!("\t* {}", info_store.to_string()))
+            .collect::<Vec<String>>()
+            .join("\n");
+        let inp_string = String::from(input);
+        for store in AvailableInfoStores::iter() {
+            if inp_string == store.to_string() {
+                return Ok(store);
+            }
+        }
+        Err(format!(
+            "Unknown info storage type.\n Available storages:\n{}",
+            available_stores
+        ))
+    }
+}
+
+impl AvailableInfoStores {
+    /// Convert `AvailableInfoStores` to the impl `InfoStorage`.
+    ///
+    /// # Params
+    /// `config` - Rustus configuration.
+    ///
+    pub async fn get(
+        &self,
+        config: &RustusConf,
+    ) -> RustusResult<Box<dyn InfoStorage + Sync + Send>> {
+        match self {
+            Self::Files => Ok(Box::new(file_info_storage::FileInfoStorage::new(
+                config.clone(),
+            ))),
+            #[cfg(feature = "db_info_storage")]
+            Self::DB => Ok(Box::new(
+                db_info_storage::DBInfoStorage::new(config.clone()).await?,
+            )),
+            #[cfg(feature = "redis_info_storage")]
+            AvailableInfoStores::Redis => Ok(Box::new(
+                redis_info_storage::RedisStorage::new(config.clone()).await?,
+            )),
+        }
+    }
+}
diff --git a/src/info_storages/file_info.rs b/src/info_storages/models/file_info.rs
similarity index 100%
rename from src/info_storages/file_info.rs
rename to src/info_storages/models/file_info.rs
diff --git a/src/info_storages/models/info_store.rs b/src/info_storages/models/info_store.rs
new file mode 100644
index 0000000000000000000000000000000000000000..66418e0317343f45eb2873bdf2fa1f57ae8a3055
--- /dev/null
+++ b/src/info_storages/models/info_store.rs
@@ -0,0 +1,42 @@
+use crate::errors::RustusResult;
+use crate::info_storages::FileInfo;
+use async_trait::async_trait;
+
+/// Trait for every info storage.
+///
+/// This trait defines required functions
+/// for building your own info storage.
+#[async_trait]
+pub trait InfoStorage {
+    /// Prepare storage for storing files.
+    ///
+    /// In this function you can prepare
+    /// you info storage. E.G. create a table in a database,
+    /// or a directory somewhere.
+    async fn prepare(&mut self) -> RustusResult<()>;
+
+    /// Set information about an upload.
+    ///
+    /// This function **must** persist information
+    /// about given upload so it can be accessed again by file_id.
+    ///
+    /// The `create` parameter is for optimizations.
+    /// It's here, because some storages like databases have to
+    /// be queried twice in order to get the information
+    /// about a file and actually store it. To bypass it
+    /// we can guarantee that this parameter will never be `true`
+    /// for any update operation.
+    async fn set_info(&self, file_info: &FileInfo, create: bool) -> RustusResult<()>;
+
+    /// Retrieve information from storage.
+    ///
+    /// This function must return information about file
+    /// from the given storage.
+    async fn get_info(&self, file_id: &str) -> RustusResult<FileInfo>;
+
+    /// This function removes information about file completely.
+    ///
+    /// This function must actually delete any stored information
+    /// associated with the given `file_id`.
+    async fn remove_info(&self, file_id: &str) -> RustusResult<()>;
+}
diff --git a/src/info_storages/models/mod.rs b/src/info_storages/models/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3ed80cfe51c67f71c90582789aea7d421b943b8c
--- /dev/null
+++ b/src/info_storages/models/mod.rs
@@ -0,0 +1,3 @@
+pub mod available_info_storages;
+pub mod file_info;
+pub mod info_store;
diff --git a/src/main.rs b/src/main.rs
index 4870ec39201adb200179319fa0810653d97fc846..f906b878a80a4251a86eb1b6ba3f96a7714b5d06 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,6 +15,7 @@ use crate::storages::Storage;
 mod config;
 mod errors;
 mod info_storages;
+mod notifiers;
 mod protocol;
 mod routes;
 mod storages;
diff --git a/src/notifiers/mod.rs b/src/notifiers/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..feb8e349067b88a2236e0a1ffacf45081512f878
--- /dev/null
+++ b/src/notifiers/mod.rs
@@ -0,0 +1,2 @@
+mod models;
+mod notifier;
diff --git a/src/notifiers/models/message.rs b/src/notifiers/models/message.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4006433c5d8ed507aeb2214180abea469dd71ca6
--- /dev/null
+++ b/src/notifiers/models/message.rs
@@ -0,0 +1,7 @@
+use crate::info_storages::FileInfo;
+use actix_web::HttpRequest;
+
+pub struct Message<'a> {
+    request: &'a HttpRequest,
+    file_info: FileInfo,
+}
diff --git a/src/notifiers/models/mod.rs b/src/notifiers/models/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e216a501809b4e249e2d2df72e47e6e85aa7d017
--- /dev/null
+++ b/src/notifiers/models/mod.rs
@@ -0,0 +1 @@
+pub mod message;
diff --git a/src/notifiers/notifier.rs b/src/notifiers/notifier.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f71f3cdd8681f54d9e916aa24983a9c51640e72a
--- /dev/null
+++ b/src/notifiers/notifier.rs
@@ -0,0 +1,6 @@
+use async_trait::async_trait;
+
+#[async_trait]
+trait Notifier {
+    async fn send_message();
+}
diff --git a/src/routes.rs b/src/routes.rs
index ba878f8b21fd9d28d4a10f420d9f56f9f80f9117..d7310952a278edaff27b0d6e626dfa5332cdab7e 100644
--- a/src/routes.rs
+++ b/src/routes.rs
@@ -3,6 +3,8 @@ use actix_web::HttpResponse;
 use crate::errors::{RustusError, RustusResult};
 
 /// Default response to all unknown URLs.
+/// All protocol urls can be found
+/// at `crate::protocol::*`.
 #[allow(clippy::unused_async)]
 pub async fn not_found() -> RustusResult<HttpResponse> {
     Err(RustusError::FileNotFound)
diff --git a/src/storages/mod.rs b/src/storages/mod.rs
index 33bb9b0c989e5b68ce8e14e0d3b759c125611db5..083458b5caff04176d39a5ab2de45d0f6a007473 100644
--- a/src/storages/mod.rs
+++ b/src/storages/mod.rs
@@ -1,120 +1,5 @@
-use std::collections::HashMap;
-use std::str::FromStr;
-
-use actix_files::NamedFile;
-use async_trait::async_trait;
-use derive_more::{Display, From};
-
-use crate::errors::RustusResult;
-use crate::info_storages::{FileInfo, InfoStorage};
-use crate::RustusConf;
-
 pub mod file_storage;
+mod models;
 
-/// Enum of available Storage implementations.
-#[derive(PartialEq, From, Display, Clone, Debug)]
-pub enum AvailableStores {
-    #[display(fmt = "FileStorage")]
-    FileStorage,
-}
-
-impl FromStr for AvailableStores {
-    type Err = String;
-
-    /// This function converts string to the `AvailableStore` item.
-    /// This function is used by structopt to parse CLI parameters.
-    ///
-    /// # Params
-    /// `input` - input string.
-    fn from_str(input: &str) -> Result<AvailableStores, Self::Err> {
-        match input {
-            "file_storage" => Ok(AvailableStores::FileStorage),
-            _ => Err(String::from("Unknown storage type")),
-        }
-    }
-}
-
-impl AvailableStores {
-    /// Convert `AvailableStores` to the Storage.
-    ///
-    /// # Params
-    /// `config` - Rustus configuration.
-    ///
-    pub fn get(
-        &self,
-        config: &RustusConf,
-        info_storage: Box<dyn InfoStorage + Sync + Send>,
-    ) -> Box<dyn Storage + Send + Sync> {
-        #[allow(clippy::single_match)]
-        match self {
-            Self::FileStorage => {
-                Box::new(file_storage::FileStorage::new(config.clone(), info_storage))
-            }
-        }
-    }
-}
-
-#[async_trait]
-pub trait Storage {
-    /// Prepare storage before starting up server.
-    ///
-    /// Function to check if configuration is correct
-    /// and prepare storage E.G. create connection pool,
-    /// or directory for files.
-    async fn prepare(&mut self) -> RustusResult<()>;
-
-    /// Get file information.
-    ///
-    /// This method returns all information about file.
-    ///
-    /// # Params
-    /// `file_id` - unique file identifier.
-    async fn get_file_info(&self, file_id: &str) -> RustusResult<FileInfo>;
-
-    /// Get contents of a file.
-    ///
-    /// This method must return NamedFile since it
-    /// is compatible with ActixWeb files interface.
-    ///
-    /// # Params
-    /// `file_id` - unique file identifier.
-    async fn get_contents(&self, file_id: &str) -> RustusResult<NamedFile>;
-
-    /// Add bytes to the file.
-    ///
-    /// This method is used to append bytes to some file.
-    /// It returns new offset.
-    ///
-    /// # Params
-    /// `file_id` - unique file identifier;
-    /// `request_offset` - offset from the client.
-    /// `bytes` - bytes to append to the file.
-    async fn add_bytes(
-        &self,
-        file_id: &str,
-        request_offset: usize,
-        bytes: &[u8],
-    ) -> RustusResult<usize>;
-
-    /// Create file in storage.
-    ///
-    /// This method is used to generate unique file id, create file and store information about it.
-    ///
-    /// # Params
-    /// `file_size` - Size of a file. It may be None if size is deferred;
-    /// `metadata` - Optional file meta-information;
-    async fn create_file(
-        &self,
-        file_size: Option<usize>,
-        metadata: Option<HashMap<String, String>>,
-    ) -> RustusResult<String>;
-
-    /// Remove file from storage
-    ///
-    /// This method removes file and all associated
-    /// object if any.
-    ///
-    /// # Params
-    /// `file_id` - unique file identifier;
-    async fn remove_file(&self, file_id: &str) -> RustusResult<()>;
-}
+pub use models::available_stores::AvailableStores;
+pub use models::storage::Storage;
diff --git a/src/storages/models/available_stores.rs b/src/storages/models/available_stores.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e13c670e1dd9ea096aa633c7cd1b42a703adfb4a
--- /dev/null
+++ b/src/storages/models/available_stores.rs
@@ -0,0 +1,48 @@
+use crate::info_storages::InfoStorage;
+use crate::storages::file_storage;
+use crate::{RustusConf, Storage};
+use derive_more::{Display, From};
+use std::str::FromStr;
+
+/// Enum of available Storage implementations.
+#[derive(PartialEq, From, Display, Clone, Debug)]
+pub enum AvailableStores {
+    #[display(fmt = "FileStorage")]
+    FileStorage,
+}
+
+impl FromStr for AvailableStores {
+    type Err = String;
+
+    /// This function converts string to the `AvailableStore` item.
+    /// This function is used by structopt to parse CLI parameters.
+    ///
+    /// # Params
+    /// `input` - input string.
+    fn from_str(input: &str) -> Result<AvailableStores, Self::Err> {
+        match input {
+            "file_storage" => Ok(AvailableStores::FileStorage),
+            _ => Err(String::from("Unknown storage type")),
+        }
+    }
+}
+
+impl AvailableStores {
+    /// Convert `AvailableStores` to the Storage.
+    ///
+    /// # Params
+    /// `config` - Rustus configuration.
+    ///
+    pub fn get(
+        &self,
+        config: &RustusConf,
+        info_storage: Box<dyn InfoStorage + Sync + Send>,
+    ) -> Box<dyn Storage + Send + Sync> {
+        #[allow(clippy::single_match)]
+        match self {
+            Self::FileStorage => {
+                Box::new(file_storage::FileStorage::new(config.clone(), info_storage))
+            }
+        }
+    }
+}
diff --git a/src/storages/models/mod.rs b/src/storages/models/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6f58895a7ebac11e31210d33dbf7e97d1c85476f
--- /dev/null
+++ b/src/storages/models/mod.rs
@@ -0,0 +1,2 @@
+pub mod available_stores;
+pub mod storage;
diff --git a/src/storages/models/storage.rs b/src/storages/models/storage.rs
new file mode 100644
index 0000000000000000000000000000000000000000..89bed1b6d14b34d7baea66a58bd5cb6c3509e3da
--- /dev/null
+++ b/src/storages/models/storage.rs
@@ -0,0 +1,70 @@
+use crate::errors::RustusResult;
+use crate::info_storages::FileInfo;
+use actix_files::NamedFile;
+use async_trait::async_trait;
+use std::collections::HashMap;
+
+#[async_trait]
+pub trait Storage {
+    /// Prepare storage before starting up server.
+    ///
+    /// Function to check if configuration is correct
+    /// and prepare storage E.G. create connection pool,
+    /// or directory for files.
+    async fn prepare(&mut self) -> RustusResult<()>;
+
+    /// Get file information.
+    ///
+    /// This method returns all information about file.
+    ///
+    /// # Params
+    /// `file_id` - unique file identifier.
+    async fn get_file_info(&self, file_id: &str) -> RustusResult<FileInfo>;
+
+    /// Get contents of a file.
+    ///
+    /// This method must return NamedFile since it
+    /// is compatible with ActixWeb files interface.
+    ///
+    /// # Params
+    /// `file_id` - unique file identifier.
+    async fn get_contents(&self, file_id: &str) -> RustusResult<NamedFile>;
+
+    /// Add bytes to the file.
+    ///
+    /// This method is used to append bytes to some file.
+    /// It returns new offset.
+    ///
+    /// # Params
+    /// `file_id` - unique file identifier;
+    /// `request_offset` - offset from the client.
+    /// `bytes` - bytes to append to the file.
+    async fn add_bytes(
+        &self,
+        file_id: &str,
+        request_offset: usize,
+        bytes: &[u8],
+    ) -> RustusResult<usize>;
+
+    /// Create file in storage.
+    ///
+    /// This method is used to generate unique file id, create file and store information about it.
+    ///
+    /// # Params
+    /// `file_size` - Size of a file. It may be None if size is deferred;
+    /// `metadata` - Optional file meta-information;
+    async fn create_file(
+        &self,
+        file_size: Option<usize>,
+        metadata: Option<HashMap<String, String>>,
+    ) -> RustusResult<String>;
+
+    /// Remove file from storage
+    ///
+    /// This method removes file and all associated
+    /// object if any.
+    ///
+    /// # Params
+    /// `file_id` - unique file identifier;
+    async fn remove_file(&self, file_id: &str) -> RustusResult<()>;
+}