diff --git a/Cargo.lock b/Cargo.lock
index 6c5834b6..73e0b28a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2803,6 +2803,16 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "serde_path_to_error"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335"
+dependencies = [
+ "itoa",
+ "serde",
+]
+
 [[package]]
 name = "serde_qs"
 version = "0.8.5"
@@ -3107,6 +3117,7 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
+ "serde_path_to_error",
  "serde_valid",
  "serde_yaml",
  "sha2",
diff --git a/Cargo.toml b/Cargo.toml
index b23bf3b2..54ee40f6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -52,6 +52,7 @@ serde_yaml = "0.9"
 lapin = { version = "2.3.1", features = ["serde_json"] }
 futures-lite = "1.13.0"
 clap = { version = "4.4.8", features = ["derive"] }
+serde_path_to_error = "0.1.14"
 
 [dependencies.sqlx]
 version = "0.6.3"
diff --git a/migrations/20230903063840_creating_rating_tables.down.sql b/migrations/20230903063840_creating_rating_tables.down.sql
index e12e4ab3..b32b52b5 100644
--- a/migrations/20230903063840_creating_rating_tables.down.sql
+++ b/migrations/20230903063840_creating_rating_tables.down.sql
@@ -6,3 +6,5 @@ DROP INDEX idx_obj_id_rating_id;
 
 DROP table rating;
 DROP table product;
+
+DROP TYPE rate_category;
diff --git a/migrations/20230903063840_creating_rating_tables.up.sql b/migrations/20230903063840_creating_rating_tables.up.sql
index 579bef6f..28422706 100644
--- a/migrations/20230903063840_creating_rating_tables.up.sql
+++ b/migrations/20230903063840_creating_rating_tables.up.sql
@@ -1,5 +1,17 @@
 -- Add up migration script here
 
+CREATE TYPE rate_category AS ENUM (
+    'application',
+    'cloud',      
+    'stack',
+    'deploymentSpeed',
+    'documentation',
+    'design',
+    'techSupport',
+    'price',
+    'memoryUsage'
+);
+
 CREATE TABLE product (
     id integer NOT NULL, PRIMARY KEY(id),
     obj_id integer NOT NULL,
@@ -12,7 +24,7 @@ CREATE TABLE rating (
     id serial,
     user_id VARCHAR(50) NOT NULL,
     obj_id integer NOT NULL,
-    category VARCHAR(255) NOT NULL,
+    category rate_category NOT NULL,
     comment TEXT DEFAULT NULL,
     hidden BOOLEAN DEFAULT FALSE,
     rate INTEGER,
diff --git a/src/console/commands/appclient/new.rs b/src/console/commands/appclient/new.rs
index 448ac788..ada01acb 100644
--- a/src/console/commands/appclient/new.rs
+++ b/src/console/commands/appclient/new.rs
@@ -26,7 +26,7 @@ impl crate::console::commands::CallableTrait for NewCommand {
 
             //todo get user from trydirect
             let user = crate::models::user::User {
-                id: "first_name".to_string(),
+                id: format!("{}", self.user_id),
                 first_name: "first_name".to_string(),
                 last_name: "last_name".to_string(),
                 email: "email".to_string(),
diff --git a/src/db/client.rs b/src/db/client.rs
new file mode 100644
index 00000000..b8307a72
--- /dev/null
+++ b/src/db/client.rs
@@ -0,0 +1,105 @@
+use sqlx::PgPool;
+use crate::models;
+use tracing::Instrument;
+
+pub async fn update(pool: &PgPool, client: models::Client) -> Result<models::Client, String> {
+    let query_span = tracing::info_span!("Updating client into the database");
+    sqlx::query!(
+        r#"
+        UPDATE client
+        SET 
+            secret=$1,
+            updated_at=NOW() at time zone 'utc'
+        WHERE id = $2
+        "#,
+        client.secret,
+        client.id
+    )
+    .execute(pool)
+    .instrument(query_span)
+    .await
+    .map(|_|{
+        tracing::info!("Client {} have been saved to database", client.id);
+        client
+    })
+    .map_err(|err| {
+        tracing::error!("Failed to execute query: {:?}", err);
+        "".to_string()
+    })
+}
+
+pub async fn fetch(pool: &PgPool, id: i32) -> Result<Option<models::Client>, String> {
+    let query_span = tracing::info_span!("Fetching the client by ID");
+    sqlx::query_as!(
+        models::Client,
+        r#"
+        SELECT
+           id,
+           user_id,
+           secret 
+        FROM client c
+        WHERE c.id = $1
+        LIMIT 1
+        "#,
+        id,
+    )
+    .fetch_one(pool)
+    .instrument(query_span)
+    .await
+    .map(|client| Some(client))
+    .or_else(|e| {
+        match e {
+            sqlx::Error::RowNotFound => Ok(None),
+            s => {
+                tracing::error!("Failed to execute fetch query: {:?}", s);
+                Err("".to_string())
+            }
+        }
+    })
+}
+
+pub async fn count_by_user(pool: &PgPool , user_id: &String) -> Result<i64, String> {
+    let query_span = tracing::info_span!("Counting the user's clients");
+
+    sqlx::query!(
+        r#"
+        SELECT
+            count(*) as client_count
+        FROM client c 
+        WHERE c.user_id = $1
+        "#,
+        user_id.clone(),
+    )
+    .fetch_one(pool)
+    .instrument(query_span)
+    .await
+    .map(|result| {result.client_count.unwrap()})
+    .map_err(|err| {
+        tracing::error!("Failed to execute query: {:?}", err);
+        "Internal Server Error".to_string()
+    })
+}
+
+pub async fn  insert(pool: &PgPool, mut client: models::Client) -> Result<models::Client, String> {
+    let query_span = tracing::info_span!("Saving new client into the database");
+    sqlx::query!(
+        r#"
+        INSERT INTO client (user_id, secret, created_at, updated_at)
+        VALUES ($1, $2, NOW() at time zone 'utc', NOW() at time zone 'utc')
+        RETURNING id
+        "#,
+        client.user_id.clone(),
+        client.secret,
+    )
+    .fetch_one(pool)
+    .instrument(query_span)
+    .await
+    .map(move |result| {
+        client.id = result.id;
+        client
+    })
+    .map_err(|e| {
+        tracing::error!("Failed to execute query: {:?}", e);
+        "Failed to insert".to_string()
+    })
+}
diff --git a/src/db/mod.rs b/src/db/mod.rs
new file mode 100644
index 00000000..a4fe3ae7
--- /dev/null
+++ b/src/db/mod.rs
@@ -0,0 +1,4 @@
+pub mod client;
+pub mod product;
+pub mod rating;
+pub mod stack;
diff --git a/src/db/product.rs b/src/db/product.rs
new file mode 100644
index 00000000..e9c591ae
--- /dev/null
+++ b/src/db/product.rs
@@ -0,0 +1,30 @@
+use sqlx::PgPool;
+use crate::models;
+use tracing::Instrument;
+
+pub async fn fetch_by_obj(pg_pool: &PgPool, obj_id: i32) -> Result<Option<models::Product>, String> {
+    let query_span = tracing::info_span!("Check product existence by id.");
+    sqlx::query_as!(
+        models::Product,
+        r#"SELECT
+            *
+         FROM product
+         WHERE obj_id = $1
+         LIMIT 1
+         "#,
+        obj_id
+    )
+    .fetch_one(pg_pool)
+    .instrument(query_span)
+    .await
+    .map(|product| Some(product))
+    .or_else(|e| {
+        match e {
+            sqlx::Error::RowNotFound => Ok(None),
+            s => {
+                tracing::error!("Failed to execute fetch query: {:?}", s);
+                Err("".to_string())
+            }
+        }
+    })
+}
diff --git a/src/db/rating.rs b/src/db/rating.rs
new file mode 100644
index 00000000..599c49cc
--- /dev/null
+++ b/src/db/rating.rs
@@ -0,0 +1,133 @@
+use sqlx::PgPool;
+use crate::models;
+use tracing::Instrument;
+
+pub async fn fetch_all(pool: &PgPool) -> Result<Vec<models::Rating>, String> {
+    let query_span = tracing::info_span!("Fetch all ratings.");
+    sqlx::query_as!(
+        models::Rating,
+        r#"SELECT 
+            id,
+            user_id,
+            obj_id,
+            category as "category: _",
+            comment,
+            hidden,
+            rate,
+            created_at,
+            updated_at
+        FROM rating"#
+    )
+    .fetch_all(pool)
+    .instrument(query_span)
+    .await
+    .map_err(|e| {
+        tracing::error!("Failed to execute fetch query: {:?}", e);
+        "".to_string()
+    })
+}
+
+pub async fn fetch(pool: &PgPool, id: i32) -> Result<Option<models::Rating>, String> {
+    let query_span = tracing::info_span!("Fetch rating by id");
+    sqlx::query_as!(
+        models::Rating,
+        r#"SELECT 
+            id,
+            user_id,
+            obj_id,
+            category as "category: _",
+            comment,
+            hidden,
+            rate,
+            created_at,
+            updated_at
+        FROM rating
+        WHERE id=$1
+        LIMIT 1"#,
+        id
+    )
+    .fetch_one(pool)
+    .instrument(query_span)
+    .await
+    .map(|rating| Some(rating))
+    .or_else(|e| {
+        match e {
+            sqlx::Error::RowNotFound => Ok(None),
+            s => {
+                tracing::error!("Failed to execute fetch query: {:?}", s);
+                Err("".to_string())
+            }
+        }
+    })
+}
+
+pub async fn fetch_by_obj_and_user_and_category(
+    pool: &PgPool,
+    obj_id: i32,
+    user_id: String,
+    category: models::RateCategory,
+) -> Result<Option<models::Rating>, String> {
+    let query_span = tracing::info_span!("Fetch rating by obj, user and category.");
+    sqlx::query_as!(
+        models::Rating,
+        r#"SELECT 
+            id,
+            user_id,
+            obj_id,
+            category as "category: _",
+            comment,
+            hidden,
+            rate,
+            created_at,
+            updated_at
+        FROM rating
+        WHERE user_id=$1
+            AND obj_id=$2
+            AND category=$3
+        LIMIT 1"#,
+        user_id,
+        obj_id,
+        category as _ 
+    )
+    .fetch_one(pool)
+    .instrument(query_span)
+    .await
+    .map(|rating| Some(rating))
+    .or_else(|e| {
+        match e {
+            sqlx::Error::RowNotFound => Ok(None),
+            s => {
+                tracing::error!("Failed to execute fetch query: {:?}", s);
+                Err("".to_string())
+            }
+        }
+    })
+}
+
+pub async fn insert(pool: &PgPool, mut rating: models::Rating) -> Result<models::Rating, String> {
+    let query_span = tracing::info_span!("Saving new rating details into the database");
+    sqlx::query!(
+        r#"
+        INSERT INTO rating (user_id, obj_id, category, comment, hidden, rate, created_at, updated_at)
+        VALUES ($1, $2, $3, $4, $5, $6, NOW() at time zone 'utc', NOW() at time zone 'utc')
+        RETURNING id
+        "#,
+        rating.user_id,
+        rating.obj_id,
+        rating.category as _,
+        rating.comment,
+        rating.hidden,
+        rating.rate
+    )
+    .fetch_one(pool)
+    .instrument(query_span)
+    .await
+    .map(move |result| {
+        rating.id = result.id;
+        rating
+    })
+    .map_err(|e| {
+        tracing::error!("Failed to execute query: {:?}", e);
+        "Failed to insert".to_string()
+    })
+}
diff --git a/src/db/stack.rs b/src/db/stack.rs
new file mode 100644
index 00000000..92725cdb
--- /dev/null
+++ b/src/db/stack.rs
@@ -0,0 +1,103 @@
+use crate::models;
+use sqlx::PgPool;
+use tracing::Instrument;
+
+pub async fn fetch(pool: &PgPool, id: i32) -> Result<Option<models::Stack>, String> {
+    tracing::info!("Fecth stack {}", id);
+    sqlx::query_as!(
+        models::Stack,
+        r#"
+        SELECT
+            *
+        FROM user_stack
+        WHERE id=$1
+        LIMIT 1
+        "#,
+        id
+    )
+    .fetch_one(pool)
+    .await
+    .map(|stack| Some(stack))
+    .or_else(|err| match err {
+        sqlx::Error::RowNotFound => Ok(None),
+        e => {
+            tracing::error!("Failed to fetch stack, error: {:?}", e);
+            Err("Could not fetch data".to_string())
+        }
+    })
+}
+
+pub async fn fetch_by_user(pool: &PgPool, user_id: &str) -> Result<Vec<models::Stack>, String> {
+    let query_span = tracing::info_span!("Fetch stacks by user id.");
+    sqlx::query_as!(
+        models::Stack,
+        r#"
+        SELECT
+            *
+        FROM user_stack
+        WHERE user_id=$1
+        "#,
+        user_id
+    )
+    .fetch_all(pool)
+    .instrument(query_span)
+    .await
+    .map_err(|err| {
+        tracing::error!("Failed to fetch stack, error: {:?}", err);
+        "".to_string()
+    })
+}
+
+pub async fn fetch_one_by_name(pool: &PgPool, name: &str) -> Result<Option<models::Stack>, String> {
+    let query_span = tracing::info_span!("Fetch one stack by name.");
+    sqlx::query_as!(
+        models::Stack,
+        r#"
+        SELECT
+            *
+        FROM user_stack
+        WHERE name=$1
+        LIMIT 1
+        "#,
+        name
+    )
+    .fetch_one(pool)
+    .instrument(query_span)
+    .await
+    .map(|stack| Some(stack))
+    .or_else(|err| match err {
+        sqlx::Error::RowNotFound => Ok(None),
+        err => {
+            tracing::error!("Failed to fetch one stack by name, error: {:?}", err);
+            Err("".to_string())
+        }
+    })
+}
+
+pub async fn insert(pool: &PgPool, mut stack: models::Stack) -> Result<models::Stack, String> {
+    let query_span = tracing::info_span!("Saving new stack into the database");
+    sqlx::query!(
+        r#"
+        INSERT INTO user_stack (stack_id, user_id, name, body, created_at, updated_at)
+        VALUES ($1, $2, $3, $4, $5, $6)
+        RETURNING id;
+        "#,
+        stack.stack_id,
+        stack.user_id,
+        stack.name,
+        stack.body,
+        stack.created_at,
+        stack.updated_at,
+    )
+    .fetch_one(pool)
+    .instrument(query_span)
+    .await
+    .map(move |result| {
+        stack.id = result.id;
+        stack
+    })
+    .map_err(|e| {
+        tracing::error!("Failed to execute query: {:?}", e);
+        "Failed to insert".to_string()
+    })
+}
diff --git a/src/forms/rating.rs b/src/forms/rating.rs
index 76efca44..d7a4bd7e 100644
--- a/src/forms/rating.rs
+++ b/src/forms/rating.rs
@@ -12,3 +12,16 @@ pub struct Rating {
     #[validate(maximum = 10)]
     pub rate: i32, //
 }
+
+impl Into<models::Rating> for Rating {
+    fn into(self) -> models::Rating {
+        let mut rating = models::Rating::default(); 
+        rating.obj_id = self.obj_id;
+        rating.category = self.category.into(); //todo change the type of category field to the RateCategory
+        rating.hidden = Some(false); 
+        rating.rate = Some(self.rate);
+        rating.comment = self.comment; 
+
+        rating
+    }
+}
diff --git a/src/forms/stack.rs b/src/forms/stack.rs
index b67a8566..cc322330 100644
--- a/src/forms/stack.rs
+++ b/src/forms/stack.rs
@@ -1,10 +1,9 @@
-use std::collections::HashMap;
 use serde::{Deserialize, Serialize};
 use serde_json::Value;
 use serde_valid::Validate;
+use std::collections::HashMap;
 use std::fmt;
 
-
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
 pub struct Role {
     pub role: Option<Vec<String>>,
@@ -12,18 +11,18 @@ pub struct Role {
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
 pub struct Requirements {
-    #[validate(min_length=1)]
-    #[validate(max_length=10)]
+    #[validate(min_length = 1)]
+    #[validate(max_length = 10)]
     #[validate(pattern = r"^\d+\.?[0-9]+$")]
     pub cpu: Option<String>,
-    #[validate(min_length=1)]
-    #[validate(max_length=10)]
+    #[validate(min_length = 1)]
+    #[validate(max_length = 10)]
     #[validate(pattern = r"^\d+G$")]
     #[serde(rename = "disk_size")]
     pub disk_size: Option<String>,
     #[serde(rename = "ram_size")]
-    #[validate(min_length=1)]
-    #[validate(max_length=10)]
+    #[validate(min_length = 1)]
+    #[validate(max_length = 10)]
     #[validate(pattern = r"^\d+G$")]
     pub ram_size: Option<String>,
 }
@@ -31,7 +30,7 @@ pub struct Requirements {
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub struct Port {
     pub host_port: Option<String>,
-    pub container_port: Option<String>
+    pub container_port: Option<String>,
 }
 
 // #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -45,27 +44,31 @@ pub struct Port {
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
 pub struct DockerImage {
-    #[validate(min_length=3)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 50)]
     pub dockerhub_user: Option<String>,
-    #[validate(min_length=3)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 50)]
     pub dockerhub_name: Option<String>,
-    #[validate(min_length=3)]
-    #[validate(max_length=100)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 100)]
     pub dockerhub_image: Option<String>,
 }
 
-impl fmt::Display for DockerImage
-{
+impl fmt::Display for DockerImage {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let tag = "latest";
 
-        let dim = self.dockerhub_image.clone()
-            .unwrap_or("".to_string());
-        write!(f, "{}/{}:{}", self.dockerhub_user.clone()
-            .unwrap_or("trydirect".to_string()).clone(),
-                self.dockerhub_name.clone().unwrap_or(dim), tag
+        let dim = self.dockerhub_image.clone().unwrap_or("".to_string());
+        write!(
+            f,
+            "{}/{}:{}",
+            self.dockerhub_user
+                .clone()
+                .unwrap_or("trydirect".to_string())
+                .clone(),
+            self.dockerhub_name.clone().unwrap_or(dim),
+            tag
         )
     }
 }
@@ -76,61 +79,59 @@ impl AsRef<DockerImage> for App {
     }
 }
 
-
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
 pub struct StackForm {
     // #[validate(min_length=2)]
     // #[validate(max_length=255)]
-    #[serde(rename= "commonDomain")]
+    #[serde(rename = "commonDomain")]
     pub common_domain: Option<String>,
     pub domain_list: Option<DomainList>,
-    #[validate(min_length=2)]
-    #[validate(max_length=255)]
+    #[validate(min_length = 2)]
+    #[validate(max_length = 255)]
     pub stack_code: Option<String>,
-    #[validate(min_length=2)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 2)]
+    #[validate(max_length = 50)]
     pub region: String,
-    #[validate(min_length=2)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 2)]
+    #[validate(max_length = 50)]
     pub zone: Option<String>,
-    #[validate(min_length=2)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 2)]
+    #[validate(max_length = 50)]
     pub server: String,
-    #[validate(min_length=2)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 2)]
+    #[validate(max_length = 50)]
     pub os: String,
-    #[validate(min_length=3)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 50)]
     pub ssl: String,
     pub vars: Option<Vec<Var>>,
     pub integrated_features: Option<Vec<Value>>,
     pub extended_features: Option<Vec<Value>>,
     pub subscriptions: Option<Vec<String>>,
     pub form_app: Option<Vec<String>>,
-    #[validate(min_length=3)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 50)]
     pub disk_type: Option<String>,
     pub save_token: bool,
-    #[validate(min_length=10)]
-    #[validate(max_length=255)]
+    #[validate(min_length = 10)]
+    #[validate(max_length = 255)]
     pub cloud_token: String,
-    #[validate(min_length=2)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 2)]
+    #[validate(max_length = 50)]
     pub provider: String,
-    #[validate(min_length=3)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 50)]
     pub selected_plan: String,
     pub custom: Custom,
 }
 
-
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
 #[serde(rename_all = "snake_case")]
 pub struct StackPayload {
     pub(crate) id: Option<i32>,
     pub(crate) user_token: Option<String>,
     pub(crate) user_email: Option<String>,
-    #[serde(rename= "commonDomain")]
+    #[serde(rename = "commonDomain")]
     pub common_domain: String,
     pub domain_list: Option<DomainList>,
     pub region: String,
@@ -159,17 +160,15 @@ pub struct StackPayload {
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-pub struct DomainList {
-}
+pub struct DomainList {}
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
-pub struct Var {
-}
+pub struct Var {}
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub struct Price {
-    pub value: f64
+    pub value: f64,
 }
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
 pub struct Custom {
@@ -179,17 +178,17 @@ pub struct Custom {
     #[validate(minimum = 0)]
     #[validate(maximum = 10)]
     pub servers_count: u32,
-    #[validate(min_length=3)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 50)]
     pub custom_stack_code: String,
-    #[validate(min_length=3)]
-    #[validate(max_length=255)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 255)]
     pub project_git_url: Option<String>,
     pub custom_stack_category: Option<Vec<String>>,
     pub custom_stack_short_description: Option<String>,
     pub custom_stack_description: Option<String>,
-    #[validate(min_length=3)]
-    #[validate(max_length=255)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 255)]
     pub project_name: String,
     pub project_overview: Option<String>,
     pub project_description: Option<String>,
@@ -199,15 +198,14 @@ pub struct Custom {
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
 pub struct Network {
-    name: String
+    name: String,
 }
 
-
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
 pub struct App {
     #[serde(rename = "_etag")]
-    #[validate(min_length=3)]
-    #[validate(max_length=255)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 255)]
     pub etag: Option<String>,
     #[serde(rename = "_id")]
     pub id: u32,
@@ -215,14 +213,14 @@ pub struct App {
     pub created: Option<String>,
     #[serde(rename = "_updated")]
     pub updated: Option<String>,
-    #[validate(min_length=3)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 50)]
     pub name: String,
-    #[validate(min_length=3)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 50)]
     pub code: String,
-    #[validate(min_length=3)]
-    #[validate(max_length=50)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 50)]
     #[serde(rename = "type")]
     pub type_field: String,
     #[serde(flatten)]
@@ -233,7 +231,7 @@ pub struct App {
     pub docker_image: DockerImage,
     #[serde(flatten)]
     pub requirements: Requirements,
-    #[validate(minimum=1)]
+    #[validate(minimum = 1)]
     pub popularity: Option<u32>,
     pub commercial: Option<bool>,
     pub subscription: Option<Value>,
@@ -271,28 +269,28 @@ pub struct App {
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub struct Environment {
-    pub(crate) environment: Option<Vec<HashMap<String, String>>>
+    pub(crate) environment: Option<Vec<HashMap<String, String>>>,
 }
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub struct Volume {
     pub(crate) host_path: Option<String>,
-    pub(crate) container_path: Option<String>
+    pub(crate) container_path: Option<String>,
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub struct Volumes {
-    volumes: Vec<Volume>
+    volumes: Vec<Volume>,
 }
 
 // pub(crate) type Networks = Option<Vec<String>>;
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub struct ServiceNetworks {
-    pub network: Option<Vec<String>>
+    pub network: Option<Vec<String>>,
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub struct ComposeNetworks {
-    pub networks: Option<Vec<String>>
+    pub networks: Option<Vec<String>>,
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -337,8 +335,7 @@ pub struct IconLight {
 }
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
-pub struct IconDark {
-}
+pub struct IconDark {}
 
 #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
 pub struct Version {
@@ -352,14 +349,12 @@ pub struct Version {
     pub updated: Option<String>,
     pub app_id: Option<u32>,
     pub name: String,
-    #[validate(min_length=3)]
-    #[validate(max_length=20)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 20)]
     pub version: String,
     #[serde(rename = "update_status")]
     pub update_status: Option<String>,
-    #[validate(min_length=3)]
-    #[validate(max_length=20)]
+    #[validate(min_length = 3)]
+    #[validate(max_length = 20)]
     pub tag: String,
 }
-
-
diff --git a/src/helpers/json.rs b/src/helpers/json.rs
index 8990788d..952d7680 100644
--- a/src/helpers/json.rs
+++ b/src/helpers/json.rs
@@ -1,7 +1,6 @@
-use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorInternalServerError, ErrorNotFound};
+use actix_web::error::{ErrorBadRequest, ErrorConflict, ErrorInternalServerError, ErrorNotFound, ErrorUnauthorized};
 use actix_web::web::Json;
 use actix_web::Error;
-use actix_web::Result;
 use serde_derive::Serialize;
 
 #[derive(Serialize)]
@@ -64,30 +63,37 @@ where
         serde_json::to_string(&json_response).unwrap()
     }
 
-    pub(crate) fn ok<I: Into<String>>(self, msg: I) -> Result<Json<JsonResponse<T>>, Error> {
-        Ok(Json(self.set_msg(msg).to_json_response()))
+    pub(crate) fn ok<I: Into<String>>(self, msg: I) -> Json<JsonResponse<T>> {
+        Json(self.set_msg(msg).to_json_response())
     }
 
     pub(crate) fn bad_request<I: Into<String>>(
         self,
         msg: I,
-    ) -> Result<Json<JsonResponse<T>>, Error> {
-        Err(ErrorBadRequest(self.set_msg(msg).to_string()))
+    ) -> Error {
+        ErrorBadRequest(self.set_msg(msg).to_string())
     }
 
-    pub(crate) fn not_found<I: Into<String>>(self, msg: I) -> Result<Json<JsonResponse<T>>, Error> {
-        Err(ErrorNotFound(self.set_msg(msg).to_string()))
+    pub(crate) fn not_found<I: Into<String>>(self, msg: I) -> Error {
+        ErrorNotFound(self.set_msg(msg).to_string())
     }
 
     pub(crate) fn internal_server_error<I: Into<String>>(
         self,
         msg: I,
-    ) -> Result<Json<JsonResponse<T>>, Error> {
-        Err(ErrorInternalServerError(self.set_msg(msg).to_string()))
+    ) -> Error {
+        ErrorInternalServerError(self.set_msg(msg).to_string())
     }
 
-    pub(crate) fn conflict<I: Into<String>>(self, msg: I) -> Result<Json<JsonResponse<T>>, Error> {
-        Err(ErrorConflict(self.set_msg(msg).to_string()))
+    pub(crate) fn unauthorized<I: Into<String>>(
+        self,
+        msg: I,
+    ) -> Error {
+        ErrorUnauthorized(self.set_msg(msg).to_string())
+    }
+ 
+    pub(crate) fn conflict<I: Into<String>>(self, msg: I) -> Error {
+        ErrorConflict(self.set_msg(msg).to_string())
     }
 }
 
diff --git a/src/lib.rs b/src/lib.rs
index 37e4fae9..3c6af7cc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,6 @@
 pub mod configuration;
 pub mod console;
+pub mod db;
 pub mod forms;
 pub mod helpers;
 mod middleware;
diff --git a/src/middleware/client.rs b/src/middleware/client.rs
index 27aa97b7..60bce270 100644
--- a/src/middleware/client.rs
+++ b/src/middleware/client.rs
@@ -1,7 +1,6 @@
 use crate::helpers::JsonResponse;
 use crate::models::Client;
 use actix_http::header::CONTENT_LENGTH;
-use actix_web::error::{ErrorForbidden, ErrorInternalServerError, ErrorNotFound, PayloadError};
 use actix_web::web::BytesMut;
 use actix_web::HttpMessage;
 use futures::future::{FutureExt, LocalBoxFuture};
diff --git a/src/middleware/trydirect.rs b/src/middleware/trydirect.rs
index bbe5e4bf..e40f89b1 100644
--- a/src/middleware/trydirect.rs
+++ b/src/middleware/trydirect.rs
@@ -1,5 +1,5 @@
 use crate::{models, configuration::Settings, forms::user::UserForm, helpers::JsonResponse};
-use actix_web::{web, dev::ServiceRequest, Error, HttpMessage, error::{ErrorInternalServerError, ErrorUnauthorized}};
+use actix_web::{web, dev::ServiceRequest, Error, HttpMessage};
 use actix_web_httpauth::extractors::bearer::BearerAuth;
 use futures::future::{FutureExt};
 use reqwest::header::{ACCEPT, CONTENT_TYPE};
@@ -9,14 +9,15 @@ use std::sync::Arc;
 pub async fn bearer_guard( req: ServiceRequest, credentials: BearerAuth) -> Result<ServiceRequest, (Error, ServiceRequest)> {
     let settings = req.app_data::<web::Data<Settings>>().unwrap();
     let token = credentials.token();
-    let user = fetch_user(settings.auth_url.as_str(), token).await;
-    if let Err(err) = user {
-        return Err((ErrorUnauthorized(JsonResponse::<i32>::build().set_msg(err).to_string()), req));
-    }
+    let user = match fetch_user(settings.auth_url.as_str(), token).await {
+        Ok(user) => user,
+        Err(err) => {
+            return Err((JsonResponse::<i32>::build().unauthorized(err), req));
+        }
+    };
 
-    let user = user.unwrap();
     if req.extensions_mut().insert(Arc::new(user)).is_some() {
-        return Err((ErrorUnauthorized(JsonResponse::<i32>::build().set_msg("user already logged").to_string()), req));
+        return Err((JsonResponse::<i32>::build().unauthorized("user already logged"), req));
     }
 
     Ok(req)
diff --git a/src/models/mod.rs b/src/models/mod.rs
index b6951144..a17ea327 100644
--- a/src/models/mod.rs
+++ b/src/models/mod.rs
@@ -1,4 +1,7 @@
 mod client;
+mod product;
+mod ratecategory;
+mod rules;
 pub mod rating;
 pub mod stack;
 pub mod user;
@@ -7,3 +10,6 @@ pub use client::*;
 pub use rating::*;
 pub use stack::*;
 pub use user::*;
+pub use product::*;
+pub use ratecategory::*;
+pub use rules::*;
diff --git a/src/models/product.rs b/src/models/product.rs
new file mode 100644
index 00000000..992818db
--- /dev/null
+++ b/src/models/product.rs
@@ -0,0 +1,16 @@
+use chrono::{DateTime, Utc};
+
+pub struct Product {
+    // Product - is an external object that we want to store in the database,
+    // that can be a stack or an app in the stack. feature, service, web app etc.
+    // id - is a unique identifier for the product
+    // user_id - is a unique identifier for the user
+    // rating - is a rating of the product
+    // product type stack & app,
+    // id is generated based on the product type and external obj_id
+    pub id: i32,          //primary key, for better data management
+    pub obj_id: i32,      // external product ID db, no autoincrement, example: 100
+    pub obj_type: String, // stack | app, unique index
+    pub created_at: DateTime<Utc>,
+    pub updated_at: DateTime<Utc>,
+}
diff --git a/src/models/ratecategory.rs b/src/models/ratecategory.rs
new file mode 100644
index 00000000..8228ae0e
--- /dev/null
+++ b/src/models/ratecategory.rs
@@ -0,0 +1,27 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(sqlx::Type, Serialize, Deserialize, Debug, Clone, Copy)]
+#[sqlx(rename_all = "lowercase", type_name = "rate_category")]
+pub enum RateCategory {
+    Application, // app, feature, extension
+    Cloud,       // is user satisfied working with this cloud
+    Stack,       // app stack
+    DeploymentSpeed,
+    Documentation,
+    Design,
+    TechSupport,
+    Price,
+    MemoryUsage,
+}
+
+impl Into<String> for RateCategory {
+    fn into(self) -> String {
+        format!("{:?}", self)
+    }
+}
+
+impl Default for RateCategory {
+    fn default() -> Self {
+        RateCategory::Application
+    }
+}
diff --git a/src/models/rating.rs b/src/models/rating.rs
index c9ba7054..e1522dea 100644
--- a/src/models/rating.rs
+++ b/src/models/rating.rs
@@ -1,58 +1,16 @@
 use chrono::{DateTime, Utc};
 use serde::{Deserialize, Serialize};
-
-pub struct Product {
-    // Product - is an external object that we want to store in the database,
-    // that can be a stack or an app in the stack. feature, service, web app etc.
-    // id - is a unique identifier for the product
-    // user_id - is a unique identifier for the user
-    // rating - is a rating of the product
-    // product type stack & app,
-    // id is generated based on the product type and external obj_id
-    pub id: i32,          //primary key, for better data management
-    pub obj_id: i32,      // external product ID db, no autoincrement, example: 100
-    pub obj_type: String, // stack | app, unique index
-    pub created_at: DateTime<Utc>,
-    pub updated_at: DateTime<Utc>,
-}
+use crate::models;
 
 #[derive(Debug, Serialize, Default)]
 pub struct Rating {
     pub id: i32,
     pub user_id: String, // external user_id, 100, taken using token (middleware?)
     pub obj_id: i32,     // id of the external object
-    pub category: String, // rating of product | rating of service etc
+    pub category: models::RateCategory, // rating of product | rating of service etc
     pub comment: Option<String>, // always linked to a product
     pub hidden: Option<bool>, // rating can be hidden for non-adequate user behaviour
     pub rate: Option<i32>,
     pub created_at: DateTime<Utc>,
     pub updated_at: DateTime<Utc>,
 }
-
-
-
-#[derive(sqlx::Type, Serialize, Deserialize, Debug, Clone, Copy)]
-#[sqlx(rename_all = "lowercase", type_name = "varchar")]
-pub enum RateCategory {
-    Application, // app, feature, extension
-    Cloud,       // is user satisfied working with this cloud
-    Stack,       // app stack
-    DeploymentSpeed,
-    Documentation,
-    Design,
-    TechSupport,
-    Price,
-    MemoryUsage,
-}
-
-impl Into<String> for RateCategory {
-    fn into(self) -> String {
-        format!("{:?}", self)
-    }
-}
-
-pub struct Rules {
-    //-> Product.id
-    // example: allow to add only a single comment
-    comments_per_user: i32, // default = 1
-}
diff --git a/src/models/rules.rs b/src/models/rules.rs
new file mode 100644
index 00000000..58afbd97
--- /dev/null
+++ b/src/models/rules.rs
@@ -0,0 +1,5 @@
+pub struct Rules {
+    //-> Product.id
+    // example: allow to add only a single comment
+    comments_per_user: i32, // default = 1
+}
diff --git a/src/models/stack.rs b/src/models/stack.rs
index f9ce272e..a808f130 100644
--- a/src/models/stack.rs
+++ b/src/models/stack.rs
@@ -1,13 +1,13 @@
 use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
 use serde_json::Value;
 use uuid::Uuid;
-use serde::{Serialize,Deserialize};
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct Stack {
-    pub id: i32,       // id - is a unique identifier for the app stack
-    pub stack_id: Uuid, // external stack ID
-    pub user_id: String,  // external unique identifier for the user
+    pub id: i32,         // id - is a unique identifier for the app stack
+    pub stack_id: Uuid,  // external stack ID
+    pub user_id: String, // external unique identifier for the user
     pub name: String,
     // pub body: sqlx::types::Json<String>,
     pub body: Value, //json type
@@ -15,12 +15,26 @@ pub struct Stack {
     pub updated_at: DateTime<Utc>,
 }
 
+impl Stack {
+    pub fn new(user_id: String, name: String, body: Value) -> Self {
+        Self {
+            id: 0,
+            stack_id: Uuid::new_v4(),
+            user_id: user_id,
+            name: name,
+            body: body,
+            created_at: Utc::now(),
+            updated_at: Utc::now(),
+        }
+    }
+}
+
 impl Default for Stack {
     fn default() -> Self {
         Stack {
             user_id: "".to_string(),
             name: "".to_string(),
-                ..Default::default()
+            ..Default::default()
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/routes/client/add.rs b/src/routes/client/add.rs
index 8883f25e..b3d90d94 100644
--- a/src/routes/client/add.rs
+++ b/src/routes/client/add.rs
@@ -2,6 +2,7 @@ use crate::configuration::Settings;
 use crate::helpers::client;
 use crate::helpers::JsonResponse;
 use crate::models;
+use crate::db;
 use actix_web::{post, web, Responder, Result};
 use sqlx::PgPool;
 use tracing::Instrument;
@@ -14,10 +15,10 @@ pub async fn add_handler(
     settings: web::Data<Settings>,
     pool: web::Data<PgPool>,
 ) -> Result<impl Responder> {
-    match add_handler_inner(&user.id, settings, pool).await {
-        Ok(client) => JsonResponse::build().set_item(client).ok("Ok"),
-        Err(msg) => JsonResponse::build().bad_request(msg),
-    }
+    add_handler_inner(&user.id, settings, pool)
+        .await
+        .map(|client| JsonResponse::build().set_item(client).ok("Ok"))
+        .map_err(|err| JsonResponse::<models::Client>::build().bad_request(err))
 }
 
 pub async fn add_handler_inner(
@@ -25,58 +26,13 @@ pub async fn add_handler_inner(
     settings: web::Data<Settings>,
     pool: web::Data<PgPool>,
 ) -> Result<models::Client, String> {
-    let client_count = db_count_clients_by_user(pool.get_ref(), user_id).await?;
+    let client_count = db::client::count_by_user(pool.get_ref(), user_id).await?;
     if client_count >= settings.max_clients_number {
         return Err("Too many clients created".to_string());
     }
 
     let client = create_client(pool.get_ref(), user_id).await?;
-    db_insert_client(pool.get_ref(), client).await
-}
-
-async fn db_count_clients_by_user(pool: &PgPool , user_id: &String) -> Result<i64, String> {
-    let query_span = tracing::info_span!("Counting the user's clients");
-
-    sqlx::query!(
-        r#"
-        SELECT
-            count(*) as client_count
-        FROM client c 
-        WHERE c.user_id = $1
-        "#,
-        user_id.clone(),
-    )
-    .fetch_one(pool)
-    .instrument(query_span)
-    .await
-    .map(|result| {result.client_count.unwrap()})
-    .map_err(|err| {
-        tracing::error!("Failed to execute query: {:?}", err);
-        "Internal Server Error".to_string()
-    })
-}
-
-async fn  db_insert_client(pool: &PgPool, mut client: models::Client) -> Result<models::Client, String> {
-    let query_span = tracing::info_span!("Saving new client into the database");
-    sqlx::query!(
-        r#"
-        INSERT INTO client (user_id, secret, created_at, updated_at)
-        VALUES ($1, $2, NOW() at time zone 'utc', NOW() at time zone 'utc')
-        RETURNING id
-        "#,
-        client.user_id.clone(),
-        client.secret,
-    )
-    .fetch_one(pool)
-    .instrument(query_span)
-    .await
-    .map(move |result| {
-        client.id = result.id;
-        client
-    }).map_err(|e| {
-        tracing::error!("Failed to execute query: {:?}", e);
-        "Failed to insert".to_string()
-    })
+    db::client::insert(pool.get_ref(), client).await
 }
 
 async fn create_client(pool: &PgPool, user_id: &String) -> Result<models::Client, String> {
diff --git a/src/routes/client/disable.rs b/src/routes/client/disable.rs
index a513bd53..057a183f 100644
--- a/src/routes/client/disable.rs
+++ b/src/routes/client/disable.rs
@@ -1,6 +1,7 @@
 use crate::configuration::Settings;
 use crate::helpers::JsonResponse;
 use crate::models;
+use crate::db;
 use actix_web::{put, web, Responder, Result};
 use sqlx::PgPool;
 use tracing::Instrument;
@@ -14,72 +15,19 @@ pub async fn disable_handler(
     pool: web::Data<PgPool>,
     path: web::Path<(i32,)>,
 ) -> Result<impl Responder> {
-    match async {
         let client_id = path.0;
-        let mut client = db_fetch_client_by_id(pool.get_ref(), client_id).await?; 
+        let mut client = db::client::fetch(pool.get_ref(), client_id)
+            .await
+            .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
+            .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?; 
+
         if client.secret.is_none() {
-            return Err("client is not active".to_string());
+            return Err(JsonResponse::<models::Client>::build().bad_request("client is not active"));
         }
 
         client.secret = None;
-        db_update_client(pool.get_ref(), client).await
-    }.await {
-        Ok(client) => {
-            JsonResponse::build().set_item(client).ok("success")
-        }
-        Err(msg) => {
-            JsonResponse::<models::Client>::build().bad_request(msg)
-        }
-    }
-}
-
-async fn db_fetch_client_by_id(pool: &PgPool, id: i32) -> Result<models::Client, String> {
-    let query_span = tracing::info_span!("Fetching the client by ID");
-    sqlx::query_as!(
-        models::Client,
-        r#"
-        SELECT
-           id, user_id, secret 
-        FROM client c
-        WHERE c.id = $1
-        "#,
-        id,
-    )
-    .fetch_one(pool)
-    .instrument(query_span)
-    .await
-    .map_err(|e| {
-        match e {
-            sqlx::Error::RowNotFound => "client not found".to_string(),
-            s => {
-                tracing::error!("Failed to execute fetch query: {:?}", s);
-                "".to_string()
-            }
-        }
-    })
-}
-
-async fn db_update_client(pool: &PgPool, client: models::Client) -> Result<models::Client , String> {
-    let query_span = tracing::info_span!("Updating client into the database");
-    sqlx::query!(
-        r#"
-        UPDATE client SET 
-            secret=$1,
-            updated_at=NOW() at time zone 'utc'
-        WHERE id = $2
-        "#,
-        client.secret,
-        client.id
-    )
-    .execute(pool)
-    .instrument(query_span)
-    .await
-    .map(|_|{
-        tracing::info!("Client {} have been saved to database", client.id);
-        client
-    })
-    .map_err(|err| {
-        tracing::error!("Failed to execute query: {:?}", err);
-        "".to_string()
-    })
+        db::client::update(pool.get_ref(), client)
+            .await
+            .map(|client| JsonResponse::build().set_item(client).ok("success"))
+            .map_err(|msg| JsonResponse::<models::Client>::build().bad_request(msg))
 }
diff --git a/src/routes/client/enable.rs b/src/routes/client/enable.rs
index 6f10bebe..5669accc 100644
--- a/src/routes/client/enable.rs
+++ b/src/routes/client/enable.rs
@@ -2,9 +2,10 @@ use crate::configuration::Settings;
 use crate::helpers::client;
 use crate::helpers::JsonResponse;
 use crate::models;
+use crate::db;
 use actix_web::{put, web, Responder, Result};
-use sqlx::PgPool;
 use tracing::Instrument;
+use sqlx::PgPool;
 use std::sync::Arc;
 
 #[tracing::instrument(name = "Enable client.")]
@@ -15,72 +16,24 @@ pub async fn enable_handler(
     pool: web::Data<PgPool>,
     path: web::Path<(i32,)>,
 ) -> Result<impl Responder> {
-    match async {
-        let client_id = path.0;
-        let mut client = db_fetch_client_by_id(pool.get_ref(), client_id).await?; 
-        if client.secret.is_some() {
-            return Err("client is already active".to_string());
-        }
+    let client_id = path.0;
+    let mut client = db::client::fetch(pool.get_ref(), client_id)
+        .await
+        .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
+        .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?
+        ; 
 
-        client.secret = Some(client::generate_secret(pool.get_ref(), 255).await?);
-        db_update_client(pool.get_ref(), client).await
-    }.await {
-        Ok(client) => {
-            JsonResponse::build().set_item(client).ok("success")
-        }
-        Err(msg) => {
-            JsonResponse::<models::Client>::build().bad_request(msg)
-        }
+    if client.secret.is_some() {
+        return Err(JsonResponse::<models::Client>::build().bad_request("client is already active"));
     }
-}
 
-async fn db_fetch_client_by_id(pool: &PgPool, id: i32) -> Result<models::Client, String> {
-    let query_span = tracing::info_span!("Fetching the client by ID");
-    sqlx::query_as!(
-        models::Client,
-        r#"
-        SELECT
-           id, user_id, secret 
-        FROM client c
-        WHERE c.id = $1
-        "#,
-        id,
-    )
-    .fetch_one(pool)
-    .instrument(query_span)
-    .await
-    .map_err(|e| {
-        match e {
-            sqlx::Error::RowNotFound => "client not found".to_string(),
-            s => {
-                tracing::error!("Failed to execute fetch query: {:?}", s);
-                "".to_string()
-            }
-        }
-    })
-}
+    client.secret = client::generate_secret(pool.get_ref(), 255)
+        .await
+        .map(|secret| Some(secret))
+        .map_err(|err| JsonResponse::<models::Client>::build().bad_request(err))?;
 
-async fn db_update_client(pool: &PgPool, client: models::Client) -> Result<models::Client, String> {
-    let query_span = tracing::info_span!("Updating client into the database");
-    sqlx::query!(
-        r#"
-        UPDATE client SET 
-            secret=$1,
-            updated_at=NOW() at time zone 'utc'
-        WHERE id = $2
-        "#,
-        client.secret,
-        client.id
-    )
-    .execute(pool)
-    .instrument(query_span)
-    .await
-    .map(|_|{
-        tracing::info!("Client {} have been saved to database", client.id);
-        client
-    })
-    .map_err(|err| {
-        tracing::error!("Failed to execute query: {:?}", err);
-        "".to_string()
-    })
+    db::client::update(pool.get_ref(), client)
+        .await
+        .map(|client| JsonResponse::build().set_item(client).ok("success"))
+        .map_err(|err| JsonResponse::<models::Client>::build().bad_request(err))
 }
diff --git a/src/routes/client/update.rs b/src/routes/client/update.rs
index 7aa28ebc..b1003162 100644
--- a/src/routes/client/update.rs
+++ b/src/routes/client/update.rs
@@ -1,74 +1,41 @@
 use crate::helpers::client;
-use crate::models::user::User;
-use crate::models::Client;
+use crate::models;
+use crate::db;
 use crate::{configuration::Settings, helpers::JsonResponse};
-use actix_web::{error::ErrorBadRequest, put, web, Responder, Result};
+use actix_web::{put, web, Responder, Result};
 use sqlx::PgPool;
 use std::sync::Arc;
 use tracing::Instrument;
+use futures::TryFutureExt;
 
 #[tracing::instrument(name = "Update client.")]
 #[put("/{id}")]
 pub async fn update_handler(
-    user: web::ReqData<Arc<User>>,
+    user: web::ReqData<Arc<models::User>>,
     settings: web::Data<Settings>,
     pool: web::Data<PgPool>,
     path: web::Path<(i32,)>,
 ) -> Result<impl Responder> {
     let client_id = path.0;
-    let query_span = tracing::info_span!("Fetching the client by ID");
-    let mut client: Client = match sqlx::query_as!(
-        Client,
-        r#"
-        SELECT
-           id, user_id, secret 
-        FROM client c
-        WHERE c.id = $1
-        "#,
-        client_id,
-    )
-    .fetch_one(pool.get_ref())
-    .instrument(query_span)
-    .await
-    {
-        Ok(client) if client.secret.is_some() => Ok(client),
-        Ok(_client) => Err("client is not active"),
-        Err(sqlx::Error::RowNotFound) => Err("the client is not found"),
-        Err(e) => {
-            tracing::error!("Failed to execute fetch query: {:?}", e);
+    let mut client = db::client::fetch(pool.get_ref(), client_id)
+        .await
+        .map_err(|msg| JsonResponse::<models::Client>::build().internal_server_error(msg))?
+        .ok_or_else(|| JsonResponse::<models::Client>::build().not_found("not found"))?; 
 
-            Err("")
-        }
+    if client.secret.is_none() {
+        return Err(JsonResponse::<models::Client>::build().bad_request("client is not active"));
     }
-    .map_err(|s| ErrorBadRequest(JsonResponse::<Client>::build().set_msg(s).to_string()))?;
 
     client.secret = client::generate_secret(pool.get_ref(), 255)
         .await
         .map(|s| Some(s))
-        .map_err(|s| ErrorBadRequest(JsonResponse::<Client>::build().set_msg(s).to_string()))?;
+        .map_err(|msg| JsonResponse::<models::Client>::build().bad_request(msg))?;
 
-    let query_span = tracing::info_span!("Updating client into the database");
-    match sqlx::query!(
-        r#"
-        UPDATE client SET 
-            secret=$1,
-            updated_at=NOW() at time zone 'utc'
-        WHERE id = $2
-        "#,
-        client.secret,
-        client.id
-    )
-    .execute(pool.get_ref())
-    .instrument(query_span)
-    .await
-    {
-        Ok(_) => {
-            tracing::info!("Client {} have been saved to database", client.id);
-            JsonResponse::build().set_item(client).ok("success")
-        }
-        Err(e) => {
-            tracing::error!("Failed to execute query: {:?}", e);
-            JsonResponse::build().internal_server_error("")
-        }
-    }
+    db::client::update(pool.get_ref(), client)
+        .await
+        .map(|client| JsonResponse::<models::Client>::build().set_item(client).ok("success"))
+        .map_err(|err| {
+            tracing::error!("Failed to execute query: {:?}", err);
+            JsonResponse::<models::Client>::build().internal_server_error("")
+        })
 }
diff --git a/src/routes/rating/add.rs b/src/routes/rating/add.rs
index 922cee0d..48f03309 100644
--- a/src/routes/rating/add.rs
+++ b/src/routes/rating/add.rs
@@ -1,12 +1,12 @@
 use crate::forms;
 use crate::helpers::JsonResponse;
 use crate::models;
-use crate::models::user::User;
-use crate::models::RateCategory;
+use crate::db;
 use actix_web::{post, web, Responder, Result};
 use sqlx::PgPool;
 use tracing::Instrument;
 use std::sync::Arc;
+use futures::TryFutureExt;
 
 // workflow
 // add, update, list, get(user_id), ACL,
@@ -16,86 +16,28 @@ use std::sync::Arc;
 #[tracing::instrument(name = "Add rating.")]
 #[post("")]
 pub async fn add_handler(
-    user: web::ReqData<Arc<User>>,
+    user: web::ReqData<Arc<models::User>>,
     form: web::Json<forms::Rating>,
-    pool: web::Data<PgPool>,
+    pg_pool: web::Data<PgPool>,
 ) -> Result<impl Responder> {
-    let query_span = tracing::info_span!("Check product existence by id.");
-    match sqlx::query_as!(
-        models::Product,
-        r"SELECT * FROM product WHERE obj_id = $1",
-        form.obj_id
-    )
-    .fetch_one(pool.get_ref())
-    .instrument(query_span)
-    .await
-    {
-        Ok(product) => {
-            tracing::info!("Found product: {:?}", product.obj_id);
-        }
-        Err(e) => {
-            tracing::error!("Failed to fetch product: {:?}, error: {:?}", form.obj_id, e);
-            return JsonResponse::<models::Rating>::build().bad_request("Object not found");
-        }
-    };
+    let _product = db::product::fetch_by_obj(pg_pool.get_ref(), form.obj_id)
+        .await
+        .map_err(|msg| JsonResponse::<models::Rating>::build().internal_server_error(msg))?
+        .ok_or_else(|| JsonResponse::<models::Rating>::build().not_found("not found"))?
+        ; 
 
-    let query_span = tracing::info_span!("Search for existing vote.");
-    match sqlx::query!(
-        r"SELECT id FROM rating where user_id=$1 AND obj_id=$2 AND category=$3 LIMIT 1",
-        user.id,
-        form.obj_id,
-        form.category as RateCategory
-    )
-    .fetch_one(pool.get_ref())
-    .instrument(query_span)
-    .await
-    {
-        Ok(record) => {
-            tracing::info!(
-                "rating exists: {:?}, user: {}, product: {}, category: {:?}",
-                record.id,
-                user.id,
-                form.obj_id,
-                form.category
-            );
-            return JsonResponse::build().conflict("Already rated");
-        }
-        Err(sqlx::Error::RowNotFound) => {}
-        Err(e) => {
-            tracing::error!("Failed to fetch rating, error: {:?}", e);
-            return JsonResponse::build().internal_server_error("Internal Server Error");
-        }
+    let rating = db::rating::fetch_by_obj_and_user_and_category(pg_pool.get_ref(), form.obj_id, user.id.clone(), form.category)
+        .await
+        .map_err(|err| JsonResponse::<models::Rating>::build().internal_server_error(err))?;
+    if rating.is_some() {
+        return Err(JsonResponse::<models::Rating>::build().bad_request("already rated"));
     }
 
-    let query_span = tracing::info_span!("Saving new rating details into the database");
-    // Insert rating
-    match sqlx::query!(
-        r#"
-        INSERT INTO rating (user_id, obj_id, category, comment, hidden,rate,
-        created_at,
-        updated_at)
-        VALUES ($1, $2, $3, $4, $5, $6, NOW() at time zone 'utc', NOW() at time zone 'utc')
-        RETURNING id
-        "#,
-        user.id,
-        form.obj_id,
-        form.category as models::RateCategory,
-        form.comment,
-        false,
-        form.rate
-    )
-    .fetch_one(pool.get_ref())
-    .instrument(query_span)
-    .await
-    {
-        Ok(result) => {
-            tracing::info!("New rating {} have been saved to database", result.id);
+    let mut rating: models::Rating = form.into_inner().into();
+    rating.user_id = user.id.clone();
 
-            JsonResponse::build().set_id(result.id).ok("Saved")
-        }
-        Err(e) => {
-            tracing::error!("Failed to execute query: {:?}", e);
-            JsonResponse::build().internal_server_error("Failed to insert")
-        }
-    }
+    db::rating::insert(pg_pool.get_ref(), rating)
+        .await
+        .map(|rating| JsonResponse::build().set_item(rating).ok("success"))
+        .map_err(|err| JsonResponse::<models::Rating>::build().internal_server_error("Failed to insert"))
 }
diff --git a/src/routes/rating/get.rs b/src/routes/rating/get.rs
index e781d9a8..4bc0c1ff 100644
--- a/src/routes/rating/get.rs
+++ b/src/routes/rating/get.rs
@@ -1,5 +1,6 @@
 use crate::helpers::JsonResponse;
 use crate::models;
+use crate::db;
 use actix_web::{get, web, Responder, Result};
 use sqlx::PgPool;
 use tracing::Instrument;
@@ -15,53 +16,20 @@ pub async fn get_handler(
     path: web::Path<(i32,)>,
     pool: web::Data<PgPool>,
 ) -> Result<impl Responder> {
-    /// Get rating of any user
     let rate_id = path.0;
-    let query_span = tracing::info_span!("Search for rate id={}.", rate_id);
-    match sqlx::query_as!(
-        models::Rating,
-        r"SELECT * FROM rating WHERE id=$1 LIMIT 1",
-        rate_id
-    )
-    .fetch_one(pool.get_ref())
-    .instrument(query_span)
-    .await
-    {
-        Ok(rating) => {
-            tracing::info!("rating found: {:?}", rating.id);
-            return JsonResponse::build().set_item(Some(rating)).ok("OK");
-        }
-        Err(sqlx::Error::RowNotFound) => {
-            return JsonResponse::build().not_found("");
-        }
-        Err(e) => {
-            tracing::error!("Failed to fetch rating, error: {:?}", e);
-            return JsonResponse::build().internal_server_error("");
-        }
-    }
+    let rating = db::rating::fetch(pool.get_ref(), rate_id)
+        .await
+        .map_err(|_err| JsonResponse::<models::Rating>::build().internal_server_error(""))?
+        .ok_or_else(|| JsonResponse::<models::Rating>::build().not_found("not found"))?;
+
+    Ok(JsonResponse::build().set_item(rating).ok("OK"))
 }
 
 #[tracing::instrument(name = "Get all ratings.")]
 #[get("")]
 pub async fn list_handler(path: web::Path<()>, pool: web::Data<PgPool>) -> Result<impl Responder> {
-    /// Get ratings of all users
-    let query_span = tracing::info_span!("Get all rates.");
-    // let category = path.0;
-    match sqlx::query_as!(models::Rating, r"SELECT * FROM rating")
-        .fetch_all(pool.get_ref())
-        .instrument(query_span)
+    db::rating::fetch_all(pool.get_ref())
         .await
-    {
-        Ok(rating) => {
-            tracing::info!("Ratings found: {:?}", rating.len());
-            return JsonResponse::build().set_list(rating).ok("OK");
-        }
-        Err(sqlx::Error::RowNotFound) => {
-            return JsonResponse::build().not_found("");
-        }
-        Err(e) => {
-            tracing::error!("Failed to fetch rating, error: {:?}", e);
-            return JsonResponse::build().internal_server_error("");
-        }
-    }
+        .map(|ratings| JsonResponse::build().set_list(ratings).ok("OK"))
+        .map_err(|err| JsonResponse::<models::Rating>::build().internal_server_error(""))
 }
diff --git a/src/routes/stack/add.rs b/src/routes/stack/add.rs
index 7a12bfe8..ef38ac5f 100644
--- a/src/routes/stack/add.rs
+++ b/src/routes/stack/add.rs
@@ -1,128 +1,76 @@
+use crate::db;
 use crate::forms::stack::StackForm;
 use crate::helpers::JsonResponse;
 use crate::models;
-use crate::models::user::User;
-use actix_web::post;
+use actix_web::Error;
 use actix_web::{
-    web,
+    post, web,
     web::{Bytes, Data},
     Responder, Result,
 };
-use chrono::Utc;
 use serde_json::Value;
+use serde_valid::Validate;
 use sqlx::PgPool;
 use std::str;
-use serde_valid::Validate;
-use tracing::Instrument;
-use uuid::Uuid;
 use std::sync::Arc;
 
 #[tracing::instrument(name = "Add stack.")]
 #[post("")]
 pub async fn add(
     body: Bytes,
-    user: web::ReqData<Arc<User>>,
+    user: web::ReqData<Arc<models::User>>,
     pool: Data<PgPool>,
 ) -> Result<impl Responder> {
-
     // @todo ACL
-    let body_bytes = actix_web::body::to_bytes(body).await.unwrap();
-    let body_str = str::from_utf8(&body_bytes).unwrap();
-    let form = match serde_json::from_str::<StackForm>(body_str) {
-        Ok(f) => f,
-        Err(_err) => {
-            let msg = format!("Invalid data. {:?}", _err);
-            return JsonResponse::<StackForm>::build().bad_request(msg);
-        }
-    };
-
+    let form = body_into_form(body).await?;
     let stack_name = form.custom.custom_stack_code.clone();
-    tracing::debug!("form before convert {:?}", form);
-
-    let query_span = tracing::info_span!("Check project/stack existence by custom_stack_code.");
-    match sqlx::query_as!(
-        models::Stack,
-        r"SELECT * FROM user_stack WHERE name = $1",
-        stack_name
-    )
-        .fetch_one(pool.get_ref())
-        .instrument(query_span)
-        .await
-    {
-        Ok(record) => {
-            tracing::info!("record exists: id: {}, name: {}", record.id, record.name);
-            return JsonResponse::build().conflict("Stack with that name already exists"
-                .to_owned());
-        }
-        Err(sqlx::Error::RowNotFound) => {}
-        Err(e) => {
-            tracing::error!("Failed to fetch stack info, error: {:?}", e);
-            return JsonResponse::build().bad_request(format!("Internal Server Error"));
-        }
-    };
 
-    let user_id = user.id.clone();
-    let request_id = Uuid::new_v4();
-    let request_span = tracing::info_span!(
-        "Validating a new stack", %request_id,
-        commonDomain=?&form.custom.project_name,
-        region=?&form.region,
-        domainList=?&form.domain_list
-    );
-    // using `enter` is an async function
-    let _request_span_guard = request_span.enter(); // ->exit
+    check_if_stack_exists(pool.get_ref(), &stack_name).await?;
 
-    tracing::info!(
-        "request_id {} Adding '{}' '{}' as a new stack",
-        request_id,
-        form.custom.project_name,
-        form.region
-    );
+    let body: Value = serde_json::to_value::<StackForm>(form)
+        .or(serde_json::to_value::<StackForm>(StackForm::default()))
+        .unwrap();
 
-    let query_span = tracing::info_span!("Saving new stack details into the database");
+    let stack = models::Stack::new(user.id.clone(), stack_name, body);
+    db::stack::insert(pool.get_ref(), stack)
+        .await
+        .map(|stack| JsonResponse::build().set_item(stack).ok("Ok"))
+        .map_err(|_| {
+            JsonResponse::<models::Stack>::build().internal_server_error("Internal Server Error")
+        })
+}
 
-    if !form.validate().is_ok() {
-        let errors = form.validate().unwrap_err();
-        let err_msg = format!("Invalid data received {:?}", &errors.to_string());
-        tracing::debug!(err_msg);
-        return JsonResponse::build().bad_request(errors.to_string());// tmp solution
-    }
+async fn check_if_stack_exists(pool: &PgPool, stack_name: &String) -> Result<(), Error> {
+    db::stack::fetch_one_by_name(pool, stack_name)
+        .await
+        .map_err(|_| {
+            JsonResponse::<models::Stack>::build().internal_server_error("Internal Server Error")
+        })
+        .and_then(|stack| match stack {
+            Some(_) => Err(JsonResponse::<models::Stack>::build()
+                .conflict("Stack with that name already exists")),
+            None => Ok(()),
+        })
+}
 
-    let body: Value = match serde_json::to_value::<StackForm>(form) {
-        Ok(body) => body,
-        Err(err) => {
-            tracing::error!("Request_id {} error unwrap body {:?}", request_id, err);
-            serde_json::to_value::<StackForm>(StackForm::default()).unwrap()
-        }
-    };
+async fn body_into_form(body: Bytes) -> Result<StackForm, Error> {
+    let body_bytes = actix_web::body::to_bytes(body).await.unwrap();
+    let body_str = str::from_utf8(&body_bytes)
+        .map_err(|err| JsonResponse::<StackForm>::build().internal_server_error(err.to_string()))?;
+    let deserializer = &mut serde_json::Deserializer::from_str(body_str);
+    serde_path_to_error::deserialize(deserializer)
+        .map_err(|err| {
+            let msg = format!("{}:{:?}", err.path().to_string(), err);
+            JsonResponse::<StackForm>::build().bad_request(msg)
+        })
+        .and_then(|form: StackForm| {
+            if !form.validate().is_ok() {
+                let errors = form.validate().unwrap_err();
+                let err_msg = format!("Invalid data received {:?}", &errors.to_string());
+                tracing::debug!(err_msg);
+                return Err(JsonResponse::<models::Stack>::build().bad_request(errors.to_string()));
+            }
 
-    match sqlx::query!(
-        r#"
-        INSERT INTO user_stack (stack_id, user_id, name, body, created_at, updated_at)
-        VALUES ($1, $2, $3, $4, $5, $6)
-        RETURNING id;
-        "#,
-        Uuid::new_v4(),
-        user_id,
-        stack_name,
-        body,
-        Utc::now(),
-        Utc::now(),
-    )
-    .fetch_one(pool.get_ref())
-    .instrument(query_span)
-    .await
-    {
-        Ok(record) => {
-            tracing::info!(
-                "req_id: {} New stack details have been saved to database",
-                request_id
-            );
-            return JsonResponse::build().set_id(record.id).ok("OK");
-        }
-        Err(e) => {
-            tracing::error!("req_id: {} Failed to execute query: {:?}", request_id, e);
-            return JsonResponse::build().internal_server_error("Internal Server Error");
-        }
-    };
+            Ok(form)
+        })
 }
diff --git a/src/routes/stack/compose.rs b/src/routes/stack/compose.rs
index 819a8865..28290902 100644
--- a/src/routes/stack/compose.rs
+++ b/src/routes/stack/compose.rs
@@ -1,129 +1,61 @@
-use actix_web::{
-    web,
-    web::{Data, Json},
-    Responder, Result,
-};
-
+use crate::db;
 use crate::helpers::stack::builder::DcBuilder;
 use crate::helpers::JsonResponse;
-use crate::models::user::User;
-use crate::models::Stack;
-use actix_web::{get, post};
+use crate::models;
+use actix_web::{get, web, web::Data, Responder, Result};
 use sqlx::PgPool;
-use std::str;
-use tracing::Instrument;
 use std::sync::Arc;
 
 #[tracing::instrument(name = "User's generate docker-compose.")]
 #[get("/{id}")]
 pub async fn add(
-    user: web::ReqData<Arc<User>>,
+    user: web::ReqData<Arc<models::User>>,
     path: web::Path<(i32,)>,
     pool: Data<PgPool>,
 ) -> Result<impl Responder> {
     let id = path.0;
-    tracing::debug!("Received id: {}", id);
-
-    let stack = match sqlx::query_as!(
-        Stack,
-        r#"
-        SELECT * FROM user_stack WHERE id=$1 AND user_id=$2 LIMIT 1
-        "#,
-        id,
-        user.id
-    )
-    .fetch_one(pool.get_ref())
-    .await
-    {
-        Ok(stack) => {
-            tracing::info!("stack found: {:?}", stack.id);
-            Some(stack)
-        }
-        Err(sqlx::Error::RowNotFound) => {
-            tracing::error!("Row not found 404");
-            None
-        }
-        Err(e) => {
-            tracing::error!("Failed to fetch stack, error: {:?}", e);
-            None
-        }
-    };
-
-    match stack {
-        Some(stack) => {
-            let id = stack.id.clone();
-            let dc = DcBuilder::new(stack);
-            let fc = dc.build();
-            tracing::debug!("Docker compose file content {:?}", fc);
-
-            return JsonResponse::build()
-                .set_id(id)
-                .set_item(fc.unwrap())
-                .ok("Success");
-        }
-        None => {
-            return JsonResponse::build().bad_request("Could not generate compose file");
-        }
-    }
+    let stack = db::stack::fetch(pool.get_ref(), id)
+        .await
+        .map_err(|err| JsonResponse::<models::Stack>::build().internal_server_error(err))
+        .and_then(|stack| match stack {
+            Some(stack) if stack.user_id != user.id => {
+                Err(JsonResponse::<models::Stack>::build().not_found("not found"))
+            }
+            Some(stack) => Ok(stack),
+            None => Err(JsonResponse::<models::Stack>::build().not_found("not found")),
+        })?;
+
+    let id = stack.id.clone();
+    let fc = DcBuilder::new(stack).build().ok_or_else(|| {
+        tracing::error!("Error. Compose builder returned an empty string");
+        JsonResponse::<models::Stack>::build().internal_server_error("troubles at building")
+    })?;
+
+    Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success"))
 }
 
 #[tracing::instrument(name = "Generate docker-compose. Admin")]
 #[get("/{id}/compose")]
 pub async fn admin(
-    user: web::ReqData<Arc<User>>,
+    user: web::ReqData<Arc<models::User>>,
     path: web::Path<(i32,)>,
     pool: Data<PgPool>,
 ) -> Result<impl Responder> {
     ///  Admin function for generating compose file for specified user
     let id = path.0;
-    tracing::debug!("Received id: {}", id);
-
-    let stack = match sqlx::query_as!(
-        Stack,
-        r#"
-        SELECT * FROM user_stack WHERE id=$1 LIMIT 1
-        "#,
-        id,
-    )
-    .fetch_one(pool.get_ref())
-    .await
-    {
-        Ok(stack) => {
-            tracing::info!("Record found: {:?}", stack.id);
-            Some(stack)
-        }
-        Err(sqlx::Error::RowNotFound) => {
-            tracing::error!("Record not found");
-            None
-        }
-        Err(e) => {
-            tracing::error!("Failed to fetch stack, error: {:?}", e);
-            None
-        }
-    };
-
-    match stack {
-        Some(stack) => {
-            let id = stack.id.clone();
-            let dc = DcBuilder::new(stack);
-            let fc = match dc.build() {
-                Some(fc) => {
-                    fc
-                }
-                None => {
-                    tracing::error!("Error. Compose builder returned an empty string");
-                    "".to_string()
-                }
-
-            };
-            // tracing::debug!("Docker compose file content {:?}", fc);
-            return JsonResponse::build()
-                .set_id(id)
-                .set_item(fc).ok("Success");
-
-        }
-        None => {
-            return JsonResponse::build().bad_request("Could not generate compose file");
-        }
-    }
+    let stack = db::stack::fetch(pool.get_ref(), id)
+        .await
+        .map_err(|err| JsonResponse::<models::Stack>::build().internal_server_error(err))
+        .and_then(|stack| match stack {
+            Some(stack) => Ok(stack),
+            None => Err(JsonResponse::<models::Stack>::build().not_found("not found")),
+        })?;
+
+    let id = stack.id.clone();
+    let fc = DcBuilder::new(stack).build().ok_or_else(|| {
+        tracing::error!("Error. Compose builder returned an empty string");
+        JsonResponse::<models::Stack>::build().internal_server_error("troubles at building")
+    })?;
+
+    Ok(JsonResponse::build().set_id(id).set_item(fc).ok("Success"))
 }
diff --git a/src/routes/stack/deploy.rs b/src/routes/stack/deploy.rs
index d1224c59..1d52caa7 100644
--- a/src/routes/stack/deploy.rs
+++ b/src/routes/stack/deploy.rs
@@ -91,10 +91,10 @@ pub async fn add(
 
             assert_eq!(confirm, Confirmation::NotRequested);
             tracing::debug!("Message sent to rabbitmq");
-            return JsonResponse::<Stack>::build().set_id(id).ok("Success");
+            return Ok(JsonResponse::<Stack>::build().set_id(id).ok("Success"));
         }
         None => {
-            JsonResponse::build().internal_server_error("Deployment failed")
+            Err(JsonResponse::<Stack>::build().internal_server_error("Deployment failed"))
         }
     }
 }
diff --git a/src/routes/stack/get.rs b/src/routes/stack/get.rs
index dc8c09f7..ac21f342 100644
--- a/src/routes/stack/get.rs
+++ b/src/routes/stack/get.rs
@@ -1,83 +1,50 @@
-use crate::helpers::{JsonResponse, JsonResponseBuilder};
+use crate::db;
+use crate::helpers::JsonResponse;
 use crate::models;
-use crate::models::user::User;
 use actix_web::{get, web, Responder, Result};
 use sqlx::PgPool;
 use std::convert::From;
-use tracing::Instrument;
 use std::sync::Arc;
+use tracing::Instrument;
 
 #[tracing::instrument(name = "Get logged user stack.")]
 #[get("/{id}")]
 pub async fn item(
-    user: web::ReqData<Arc<User>>,
+    user: web::ReqData<Arc<models::User>>,
     path: web::Path<(i32,)>,
     pool: web::Data<PgPool>,
 ) -> Result<impl Responder> {
     /// Get stack apps of logged user only
     let (id,) = path.into_inner();
 
-    tracing::info!("User {:?} gets stack by id {:?}", user.id, id);
-    match sqlx::query_as!(
-        models::Stack,
-        r#"
-        SELECT * FROM user_stack WHERE id=$1 AND user_id=$2 LIMIT 1
-        "#,
-        id,
-        user.id
-    )
-    .fetch_one(pool.get_ref())
-    .await
-    {
-        Ok(stack) => {
-            tracing::info!("Stack found: {:?}", stack.id,);
-            return JsonResponse::build().set_item(Some(stack)).ok("OK");
-        }
-        Err(sqlx::Error::RowNotFound) => JsonResponse::build().not_found("Record not found"),
-        Err(e) => {
-            tracing::error!("Failed to fetch stack, error: {:?}", e);
-            return JsonResponse::build().internal_server_error("Could not fetch data");
-        }
-    }
+    let stack = db::stack::fetch(pool.get_ref(), id)
+        .await
+        .map_err(|err| JsonResponse::<models::Stack>::build().internal_server_error(err))
+        .and_then(|stack| match stack {
+            Some(stack) if stack.user_id != user.id => {
+                Err(JsonResponse::<models::Stack>::build().not_found("not found"))
+            }
+            Some(stack) => Ok(stack),
+            None => Err(JsonResponse::<models::Stack>::build().not_found("not found")),
+        })?;
+
+    Ok(JsonResponse::build().set_item(Some(stack)).ok("OK"))
 }
 
 #[tracing::instrument(name = "Get user's stack list.")]
 #[get("/user/{id}")]
 pub async fn list(
-    user: web::ReqData<Arc<User>>,
+    user: web::ReqData<Arc<models::User>>,
     path: web::Path<(String,)>,
     pool: web::Data<PgPool>,
 ) -> Result<impl Responder> {
     /// This is admin endpoint, used by a m2m app, client app is confidential
     /// it should return stacks by user id
     /// in order to pass validation at external deployment service
-    let (id,) = path.into_inner();
-    tracing::info!("Logged user: {:?}", user.id);
-    tracing::info!("Get stack list for user {:?}", id);
-
-    let query_span = tracing::info_span!("Get stacks by user id.");
+    let user_id = path.into_inner().0;
 
-    match sqlx::query_as!(
-        models::Stack,
-        r#"
-        SELECT * FROM user_stack WHERE user_id=$1
-        "#,
-        id
-    )
-    .fetch_all(pool.get_ref())
-    .instrument(query_span)
-    .await
-    {
-        Ok(list) => {
-            return JsonResponse::build().set_list(list).ok("OK");
-        }
-        Err(sqlx::Error::RowNotFound) => {
-            tracing::error!("No stacks found for user: {:?}", &user.id);
-            return JsonResponse::build().not_found("No stacks found for user");
-        }
-        Err(e) => {
-            tracing::error!("Failed to fetch stack, error: {:?}", e);
-            return JsonResponse::build().internal_server_error("Could not fetch".to_string());
-        }
-    }
+    db::stack::fetch_by_user(pool.get_ref(), &user_id)
+        .await
+        .map_err(|err| JsonResponse::<models::Stack>::build().internal_server_error(err))
+        .map(|stacks| JsonResponse::build().set_list(stacks).ok("OK"))
 }
diff --git a/src/routes/stack/update.rs b/src/routes/stack/update.rs
index d51c95ff..a418b532 100644
--- a/src/routes/stack/update.rs
+++ b/src/routes/stack/update.rs
@@ -43,8 +43,8 @@ pub async fn update(
         }
         Err(e) => {
             tracing::error!("Failed to fetch record: {:?}, error: {:?}", id, e);
-            return JsonResponse::<models::Stack>::build()
-                .not_found(format!("Object not found {}", id));
+            return Err(JsonResponse::<models::Stack>::build()
+                .not_found(format!("Object not found {}", id)));
         }
     };
 
@@ -72,7 +72,7 @@ pub async fn update(
         let errors = form.validate().unwrap_err();
         let err_msg = format!("Invalid data received {:?}", &errors.to_string());
         tracing::debug!(err_msg);
-        return JsonResponse::build().bad_request(errors.to_string());
+        return Err(JsonResponse::<models::Stack>::build().bad_request(errors.to_string()));
     }
 
     let body: Value = match serde_json::to_value::<StackForm>(form.into_inner()) {
@@ -106,11 +106,11 @@ pub async fn update(
                 "req_id: {} stack details have been saved to database",
                 request_id
             );
-            return JsonResponse::build().set_id(id).ok("OK");
+            return Ok(JsonResponse::<models::Stack>::build().set_id(id).ok("OK"));
         }
         Err(e) => {
             tracing::error!("req_id: {} Failed to execute query: {:?}", request_id, e);
-            return JsonResponse::build().bad_request("Internal Server Error");
+            return Err(JsonResponse::<models::Stack>::build().bad_request("Internal Server Error"));
         }
     };
 }
diff --git a/src/routes/test/deploy.rs b/src/routes/test/deploy.rs
index 51cc2014..4f36a3ae 100644
--- a/src/routes/test/deploy.rs
+++ b/src/routes/test/deploy.rs
@@ -13,5 +13,5 @@ struct DeployResponse {
 #[tracing::instrument(name = "Test deploy.")]
 #[post("/deploy")]
 pub async fn handler(client: web::ReqData<Arc<Client>>) -> Result<impl Responder> {
-    JsonResponse::build().set_item(client.into_inner()).ok("success")
+    Ok(JsonResponse::build().set_item(client.into_inner()).ok("success"))
 }
