diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8914f63bdb380ed7fe68b4841fd3137c42763dc3..fae35be50959b44bcf0eb0162250b83967df1286 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -5,6 +5,7 @@ variables:
 
 stages:
 - docker
+- build
 
 docker:front:
   image: docker
@@ -19,3 +20,19 @@ docker:front:
   - docker push $CI_REGISTRY/$CI_PROJECT_PATH/rustaheat:$CI_COMMIT_REF_SLUG
   only:
   - master
+
+  docker:back:
+  image: docker
+  services:
+    - name: docker:dind
+      alias: dockerhost
+  stage: build
+  before_script:
+  - i=0; while [ "$i" -lt 12 ]; do docker info && break; sleep 5; i=$(( i + 1 )) ; done
+  - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+  script:
+  - docker build -t $CI_REGISTRY/$CI_PROJECT_PATH/rustaheat-server:$CI_COMMIT_REF_SLUG ./server
+  - docker push $CI_REGISTRY/$CI_PROJECT_PATH/rustaheat-server:$CI_COMMIT_REF_SLUG
+  only:
+  - master
+
diff --git a/server/Dockerfile b/server/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..52d25200ac30844054ac4a4a0d37cb2e0f9ff34b
--- /dev/null
+++ b/server/Dockerfile
@@ -0,0 +1,30 @@
+FROM rust:alpine as builder
+
+#Install libc equivalent
+RUN apk add --no-cache musl-dev
+RUN apk add --no-cache pkgconfig
+RUN apk add --no-cache libressl-dev
+
+RUN --mount=type=bind,source=src,target=src \
+    --mount=type=bind,source=Cargo.toml,target=Cargo.toml \
+    --mount=type=cache,target=/app/target/ \
+    --mount=type=cache,target=/usr/local/cargo/registry/ \
+    <<EOF
+set -e
+cargo build --bin server --release
+cp ./target/release/server /bin/server
+EOF
+
+FROM alpine as runner
+# Copy the server binary to the /app directory
+
+COPY --from=builder /bin/server /bin/
+
+COPY ./data.json data.json
+COPY ./montreal.osm.pbf montreal.osm.pbf
+
+# Set any required env variables and
+ENV RUST_LOG="debug"
+EXPOSE 6942
+
+CMD ["/bin/backend"]
\ No newline at end of file
diff --git a/server/compose.yml b/server/compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..edf1a838843b457ccc2898562f2f1b4cdf977fbf
--- /dev/null
+++ b/server/compose.yml
@@ -0,0 +1,7 @@
+services:
+  server:
+    container_name: server
+    hostname: server
+    build: .
+    ports:
+      - 6942:6942
diff --git a/server/src/bin/transform.rs b/server/src/bin/transform.rs
index 9794eb9222afb0debdd06b0c7432caae8c5963b5..839f16dd15e6c7c511b562c3a69f562095598211 100644
--- a/server/src/bin/transform.rs
+++ b/server/src/bin/transform.rs
@@ -7,7 +7,10 @@ use server::map::{
 
 fn main() {
     let r = File::open(&std::path::Path::new("montreal.osm.pbf")).unwrap();
+<<<<<<< HEAD
+=======
     let time = Instant::now();
+>>>>>>> 54fe160 (Initial commit)
 
     let mut pbf = osmpbfreader::OsmPbfReader::new(r);
     let mut map = Map::default();
@@ -18,9 +21,18 @@ fn main() {
     }
     map.build();
 
+<<<<<<< HEAD
+    let time = Instant::now();
+    println!(
+        "{:#?} computed in {}s",
+        map.get(PlaceOfInterest::Restaurant, -73.76915, 45.53415),
+        time.elapsed().as_secs_f32()
+    );
+=======
     map.get(PlaceOfInterest::Restaurant, 45.53415, -73.76915);
     // println!(
     //     "{:#?} computed in {}s",
     //     time.elapsed().as_secs_f32()
     // );
+>>>>>>> 54fe160 (Initial commit)
 }
diff --git a/server/src/main.rs b/server/src/main.rs
index 639b716ca59f9997f5c3df9d30037c78b5cb6191..ed1f71ea5590c495df434dae7d5a3a5bd448540e 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -3,9 +3,12 @@ use std::{
     sync::{Arc, Mutex},
 };
 
-use poem::{listener::TcpListener, Route, Server};
+use poem::{listener::TcpListener, middleware::Cors, EndpointExt, Route, Server};
 use poem_openapi::{payload::Json, ApiResponse, Object, OpenApi, OpenApiService};
-use server::map::{interest_point::InterestPoint, Map};
+use server::map::{
+    interest_point::{InterestPoint, PlaceOfInterest},
+    Map,
+};
 struct State {
     pub map: Map,
 }
@@ -16,9 +19,9 @@ struct Api {
 
 #[derive(Object)]
 struct ServiceRequestData {
-    tags: Vec<String>,
-    latitude: f64,
-    longitude: f64,
+    pub tags: Vec<String>,
+    pub latitude: f64,
+    pub longitude: f64,
 }
 
 #[derive(Object)]
@@ -51,16 +54,22 @@ impl Api {
     }
 
     #[oai(path = "/service", method = "post")]
-    async fn index(&self, data: Json<ServiceRequestData>) -> ServiceResponse {
-        let map = self
-            .state
-            .lock()
-            .unwrap()
-            .map
-            .get_interests_point(0)
-            .clone();
-        let place_interest = map.iter().take(10).cloned().collect();
-        ServiceResponse::Ok(Json(ServiceResponseData { place_interest }))
+    async fn index(&self, input: Json<ServiceRequestData>) -> ServiceResponse {
+        let mut data: Vec<InterestPoint> = vec![];
+        for tag in input.tags.iter() {
+            let place_of_interest = PlaceOfInterest::from_str(tag.as_str(), None);
+            if let Some(place_of_interest) = place_of_interest {
+                let d = self.state.lock().unwrap().map.get(
+                    place_of_interest,
+                    input.longitude,
+                    input.latitude,
+                );
+                data.extend(d.iter().cloned());
+            }
+        }
+        ServiceResponse::Ok(Json(ServiceResponseData {
+            place_interest: data,
+        }))
     }
 }
 
@@ -76,6 +85,11 @@ async fn main() -> Result<(), std::io::Error> {
     let ui = api_service.swagger_ui();
 
     Server::new(TcpListener::bind("0.0.0.0:6942"))
-        .run(Route::new().nest("/api", api_service).nest("/", ui))
+        .run(
+            Route::new()
+                .nest("/api", api_service)
+                .nest("/", ui)
+                .with(Cors::new()),
+        )
         .await
 }
diff --git a/server/src/map/interest_point.rs b/server/src/map/interest_point.rs
index 4e1da0e4518e7ec2ba4a5676f341baf13ca6d783..034aa1ec29643a797c52b74aa6bd6e842ffc1316 100644
--- a/server/src/map/interest_point.rs
+++ b/server/src/map/interest_point.rs
@@ -1,7 +1,7 @@
 use osmpbfreader::OsmObj;
 use poem_openapi::{Enum, Object};
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Enum)]
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Enum)]
 #[repr(u8)]
 pub enum PlaceOfInterest {
     Bank = 0,
@@ -62,8 +62,8 @@ impl PlaceOfInterest {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Object)]
-struct Tag {
+#[derive(Clone, Debug, Hash, PartialEq, PartialOrd, Eq, Ord, Object)]
+pub struct Tag {
     key: String,
     value: String,
 }
@@ -74,10 +74,10 @@ impl Tag {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Object)]
+#[derive(Clone, Debug, Hash, PartialEq, PartialOrd, Eq, Ord, Object)]
 pub struct InterestPoint {
-    longitude: i32,
-    latitude: i32,
+    pub longitude: i32,
+    pub latitude: i32,
     place_interest: PlaceOfInterest,
     tags: Vec<Tag>,
 }
@@ -119,7 +119,7 @@ impl InterestPoint {
         }
     }
     pub fn get_type(&self) -> PlaceOfInterest {
-        PlaceOfInterest::Bank
+        self.place_interest
     }
     pub fn longitude(&self) -> f64 {
         self.longitude as f64 * 1e-7
diff --git a/server/src/map/interest_points.rs b/server/src/map/interest_points.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0a40c9fd41e6a5377bf1eeb58764f715bb8e5132
--- /dev/null
+++ b/server/src/map/interest_points.rs
@@ -0,0 +1,42 @@
+use std::collections::HashSet;
+
+use super::interest_point::InterestPoint;
+
+#[derive(Debug, Default)]
+pub struct InterestPoints {
+    longitude: Vec<InterestPoint>,
+    latitude: Vec<InterestPoint>,
+}
+
+const MAX_DISTANCE: f64 = 0.011;
+
+impl InterestPoints {
+    pub fn push(&mut self, interest_point: InterestPoint) {
+        self.longitude.push(interest_point.clone());
+        self.latitude.push(interest_point);
+    }
+    pub fn sort(&mut self) {
+        self.longitude.sort_unstable_by_key(|point| point.longitude);
+        self.latitude.sort_unstable_by_key(|point| point.latitude);
+    }
+    pub fn get(&self, longitude: f64, latitude: f64) -> Vec<InterestPoint> {
+        let inf = self.latitude.partition_point(|interest_point| {
+            !(interest_point.latitude() > latitude - MAX_DISTANCE)
+        });
+        let sup = self
+            .latitude
+            .partition_point(|interest_point| interest_point.latitude() < latitude + MAX_DISTANCE);
+
+        let latitude: HashSet<InterestPoint> = self.latitude[inf..sup].iter().cloned().collect();
+
+        let inf = self.longitude.partition_point(|interest_point| {
+            !(interest_point.longitude() > longitude - MAX_DISTANCE)
+        });
+        let sup = self.longitude.partition_point(|interest_point| {
+            interest_point.longitude() < longitude + MAX_DISTANCE
+        });
+
+        let longitude: HashSet<InterestPoint> = self.longitude[inf..sup].iter().cloned().collect();
+        latitude.intersection(&longitude).cloned().collect()
+    }
+}
diff --git a/server/src/map/mod.rs b/server/src/map/mod.rs
index d0806dc1f4906201a1263f59f9398dec67445ead..5c4aae807183677a5ca2a7742466697dff076493 100644
--- a/server/src/map/mod.rs
+++ b/server/src/map/mod.rs
@@ -1,21 +1,23 @@
-use self::interest_point::{InterestPoint, PlaceOfInterest};
+use self::{
+    interest_point::{InterestPoint, PlaceOfInterest},
+    interest_points::InterestPoints,
+};
 
 pub mod interest_point;
+pub mod interest_points;
 
 #[derive(Debug, Default)]
 pub struct Map {
-    interests_point: [Vec<InterestPoint>; 20],
+    pub interests_point: [InterestPoints; 20],
 }
 
-const MAX_DISTANCE: f64 = 0.011;
-
 impl Map {
     pub fn push(&mut self, interest_point: InterestPoint) {
         self.interests_point[interest_point.get_type() as usize].push(interest_point);
     }
     pub fn build(&mut self) {
         for interest_point in self.interests_point.iter_mut() {
-            interest_point.sort_unstable();
+            interest_point.sort();
         }
     }
     pub fn get(
@@ -24,26 +26,6 @@ impl Map {
         longitude: f64,
         latitude: f64,
     ) -> Vec<InterestPoint> {
-        let inf =
-            self.interests_point[place_of_interest as usize].partition_point(|interest_point| {
-                interest_point.latitude() > latitude - MAX_DISTANCE
-                    && interest_point.longitude() > longitude - MAX_DISTANCE
-            });
-        let sup =
-            self.interests_point[place_of_interest as usize].partition_point(|interest_point| {
-                interest_point.latitude() < latitude + MAX_DISTANCE
-                    && interest_point.longitude() < longitude + MAX_DISTANCE
-            });
-        println!(
-            "{} {} {}",
-            inf,
-            sup,
-            self.interests_point[place_of_interest as usize].len()
-        );
-        self.interests_point[place_of_interest as usize][inf..sup].to_vec()
-    }
-
-    pub fn get_interests_point(&self, place_of_interest: usize) -> &Vec<InterestPoint> {
-        &self.interests_point[place_of_interest]
+        self.interests_point[place_of_interest as usize].get(longitude, latitude)
     }
 }