diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..b512c09d476623ff4bf8d0d63c29b784925dbdf8
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1 @@
+node_modules
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e35789def0cfe075414a549041e95c960b8a2c40..3a29f10fe025a48e2859a3b0f067bf9061d59475 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,6 +2,8 @@ image: node:16-alpine
 stages:
   - setup
   - test
+  - build
+  - dockerize
 
 install-dependencies:
   stage: setup
@@ -33,14 +35,40 @@ install-dependencies:
     paths:
       - node_modules/.cache/nx
 
-build:
-  stage: test
-  extends: .distributed
-  script:
-    - yarn nx affected --base=HEAD~1 --target=build --parallel --max-parallel=3
-
 test:
   stage: test
   extends: .distributed
   script:
     - yarn nx affected --base=HEAD~1 --target=test --parallel --max-parallel=2
+
+build:
+  stage: build
+  only:
+    - main
+  needs:
+    - install-dependencies
+  artifacts:
+    paths:
+      - node_modules/.cache/nx
+      - dist/apps/web-graphpolaris
+  script:
+    # - yarn nx affected --base=HEAD~1 --target=build --parallel --max-parallel=3
+    # only build web-graphpolaris
+    - yarn nx build web-graphpolaris --prod
+
+build-docker:
+  image: docker:stable
+  stage: dockerize
+  tags:
+    - docker
+  only:
+    - main
+  script:
+    - docker build --progress plain -t datastropheregistry.azurecr.io/frontend:latest:latest .
+  # after_script:
+  #   - docker login datastropheregistry.azurecr.io -u $REGISTRY_USERNAME -p $REGISTRY_PASSWORD
+  #   - if [[ ! -z $CI_COMMIT_BRANCH+x ]]; then DOCKER_TAG=$CI_COMMIT_BRANCH; else DOCKER_TAG=$CI_MERGE_REQUEST_TARGET_BRANCH_NAME; fi
+  #   - docker tag $CI_PROJECT_NAME-webserver-service datastropheregistry.azurecr.io/$CI_PROJECT_NAME-webserver-service:$DOCKER_TAG
+  #   - docker push datastropheregistry.azurecr.io/$CI_PROJECT_NAME-webserver-service:$DOCKER_TAG
+  dependencies:
+    - build
diff --git a/Dockerfile b/Dockerfile
index 5ae50ee3abb63bbc32251cc96e7094c28d330d66..39c70241463b4eebd6f935ad20eb0dbee962c535 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,13 +1,12 @@
-# # Prepare nginx
-# FROM nginx:1.19-alpine
-# WORKDIR /app
+# Prepare nginx
+FROM nginx:1.19-alpine
+WORKDIR /app
 
-# # ! This copy source needs to be changed to reflect the actual app name
-# COPY ./dist/apps/frontend /usr/share/nginx/html
+COPY ./dist/apps/web-graphpolaris /usr/share/nginx/html
 
-# RUN rm /etc/nginx/conf.d/default.conf
-# COPY nginx/nginx.conf /etc/nginx/conf.d
+RUN rm /etc/nginx/conf.d/default.conf
+COPY nginx/nginx.conf /etc/nginx/conf.d
 
-# # Fire up nginx
-# EXPOSE 80
-# CMD ["nginx", "-g", "daemon off;"]
+# Fire up nginx
+EXPOSE 80
+CMD ["nginx", "-g", "daemon off;"]
diff --git a/README.md b/README.md
index 9f79b01a9bf341c469a185d07e24283bc938c6cc..ebcaddb86091a83d3a8e2df8a5d1defc53f03b89 100644
--- a/README.md
+++ b/README.md
@@ -7,23 +7,23 @@ Due to the way auth works (using a sameSite cookie), the procedure for running l
 ### MacOS / Linux
 
 1. `sudo vim /etc/hosts` open the hosts file with your prefered text editor as root
-2. Add a new row containing `127.0.0.1 local.datastrophe.science.uu.nl`, this will route traffic from `local.datastrophe.science.uu.nl` to `127.0.0.1`
+2. Add a new row containing `127.0.0.1 local.graphpolaris.com`, this will route traffic from `local.graphpolaris.com` to `127.0.0.1`
 3. `brew install mkcert` install mkcert utility
 4. `mkcert -install` generate local CA (certificate authority)
 5. Move into the /certs folder at the project root using `cd`
-6. `mkcert --key-file local-key.pem --cert-file local-cert.pem local.datastrophe.science.uu.nl` create certificates for local SSL
+6. `mkcert --key-file local-key.pem --cert-file local-cert.pem local.graphpolaris.com` create certificates for local SSL
 
 ### Windows
 
 1. Open the `hosts` file under `C:\Windows\System32\drivers\etc` using a text editor, as administrator
-2. Add a new row containing `127.0.0.1 local.datastrophe.science.uu.nl`, this will route traffic from `local.datastrophe.science.uu.nl` to `127.0.0.1`
+2. Add a new row containing `127.0.0.1 local.graphpolaris.com`, this will route traffic from `local.graphpolaris.com` to `127.0.0.1`
 3. Install mkcert using any of the ways described [here](https://github.com/FiloSottile/mkcert#windows)
 4. Open an elevated Powershell or CMD session
 5. Move into the /certs folder at the project root using `cd`
-6. `mkcert --key-file local-key.pem --cert-file local-cert.pem local.datastrophe.science.uu.nl` create certificates for local SSL
+6. `mkcert --key-file local-key.pem --cert-file local-cert.pem local.graphpolaris.com` create certificates for local SSL
 
 > No idea if the Windows steps work
 
 ## Running Locally
 
-To run the application using SSL (with these keys) simply run `nx run web-graphpolaris:dev`, or `yarn nx run web-graphpolaris:dev` if `nx` is not installed globally. This should open a window to `https://local.datastrophe.science.uu.nl:4200/` automatically.
+To run the application using SSL (with these keys) simply run `nx run web-graphpolaris:dev`, or `yarn nx run web-graphpolaris:dev` if `nx` is not installed globally. This should open a window to `https://local.graphpolaris.com:4200/` automatically.
diff --git a/apps/web-graphpolaris/project.json b/apps/web-graphpolaris/project.json
index dc9c691acc30a77b498ee4ee9c7abf79928cff15..86403889595b911f74d0f30838cc3bc428eb2251 100644
--- a/apps/web-graphpolaris/project.json
+++ b/apps/web-graphpolaris/project.json
@@ -7,7 +7,7 @@
       "executor": "@nrwl/web:dev-server",
       "options": {
         "buildTarget": "web-graphpolaris:build",
-        "host": "local.datastrophe.science.uu.nl",
+        "host": "local.graphpolaris.com",
         "port": 4200,
         "watch": true,
         "hmr": true,
@@ -19,7 +19,9 @@
     },
     "build": {
       "executor": "@nrwl/web:webpack",
-      "outputs": ["{options.outputPath}"],
+      "outputs": [
+        "{options.outputPath}"
+      ],
       "defaultConfiguration": "production",
       "options": {
         "compiler": "babel",
@@ -33,18 +35,18 @@
           "apps/web-graphpolaris/src/favicon.ico",
           "apps/web-graphpolaris/src/assets"
         ],
-        "styles": ["apps/web-graphpolaris/src/styles.scss"],
+        "styles": [
+          "apps/web-graphpolaris/src/styles.scss"
+        ],
         "scripts": [],
         "webpackConfig": "@nrwl/react/plugins/webpack"
       },
       "configurations": {
         "production": {
-          "fileReplacements": [
-            {
-              "replace": "apps/graphpolaris/src/environments/environment.ts",
-              "with": "apps/graphpolaris/src/environments/environment.prod.ts"
-            }
-          ],
+          "fileReplacements": [{
+            "replace": "apps/graphpolaris/src/environments/environment.ts",
+            "with": "apps/graphpolaris/src/environments/environment.prod.ts"
+          }],
           "optimization": true,
           "outputHashing": "all",
           "sourceMap": false,
@@ -69,14 +71,20 @@
     },
     "lint": {
       "executor": "@nrwl/linter:eslint",
-      "outputs": ["{options.outputFile}"],
+      "outputs": [
+        "{options.outputFile}"
+      ],
       "options": {
-        "lintFilePatterns": ["apps/graphpolaris/**/*.{ts,tsx,js,jsx}"]
+        "lintFilePatterns": [
+          "apps/graphpolaris/**/*.{ts,tsx,js,jsx}"
+        ]
       }
     },
     "test": {
       "executor": "@nrwl/jest:jest",
-      "outputs": ["coverage/apps/graphpolaris"],
+      "outputs": [
+        "coverage/apps/graphpolaris"
+      ],
       "options": {
         "jestConfig": "apps/web-graphpolaris/jest.config.js",
         "passWithNoTests": true
@@ -105,7 +113,9 @@
     },
     "build-storybook": {
       "executor": "@nrwl/storybook:build",
-      "outputs": ["{options.outputPath}"],
+      "outputs": [
+        "{options.outputPath}"
+      ],
       "options": {
         "uiFramework": "@storybook/react",
         "outputPath": "dist/storybook/graphpolaris",
@@ -121,4 +131,4 @@
     }
   },
   "tags": []
-}
+}
\ No newline at end of file
diff --git a/apps/web-graphpolaris/src/components/login/loginScreen.tsx b/apps/web-graphpolaris/src/components/login/loginScreen.tsx
index 93339edaadd13653822233ecf9aac3468f9f4435..fc1cf4a89f19194a218396348dbcc5cf4dc1e608 100644
--- a/apps/web-graphpolaris/src/components/login/loginScreen.tsx
+++ b/apps/web-graphpolaris/src/components/login/loginScreen.tsx
@@ -102,7 +102,7 @@ const LoginScreen = () => {
         <img
           onClick={() =>
             openSignInWindow(
-              'https://datastrophe.science.uu.nl/user/sign-in?provider=1'
+              'https://api.graphpolaris.com/user/sign-in?provider=1'
             )
           }
           src="assets/login-screen/google.png"
@@ -111,7 +111,7 @@ const LoginScreen = () => {
         <img
           onClick={() =>
             openSignInWindow(
-              'https://datastrophe.science.uu.nl/user/sign-in?provider=2'
+              'https://api.graphpolaris.com/user/sign-in?provider=2'
             )
           }
           src="assets/login-screen/github.png"
@@ -119,9 +119,7 @@ const LoginScreen = () => {
         />
         <p
           onClick={() =>
-            openSignInWindow(
-              'https://datastrophe.science.uu.nl/user/create_free/'
-            )
+            openSignInWindow('https://api.graphpolaris.com/user/create_free/')
           }
         >
           Developer
diff --git a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.module.scss b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.module.scss
index e774208e2edc900f4b6a14a50e8a742cc85745e6..755d2b41d564abe3f9e4eb41f56865ef7d2432f4 100644
--- a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.module.scss
+++ b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.module.scss
@@ -7,6 +7,10 @@
   border-radius: 3px;
 }
 
+.highlighted {
+  box-shadow: black 0 0 2px;
+}
+
 .handleLeft {
   border: 0px;
   border-radius: 0px;
diff --git a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.tsx b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.tsx
index 2598bf4581edd6c9ca1225b2b8351155289350e0..1e5f6f7ba5d6a97bd5b47daea744a3a033cd09e7 100644
--- a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.tsx
+++ b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/entitypill/entitypill.tsx
@@ -3,6 +3,7 @@ import { useTheme } from '@mui/material';
 import React, { useEffect } from 'react';
 import { FlowElement, Handle, Position } from 'react-flow-renderer';
 import styles from './entitypill.module.scss';
+import cn from 'classnames';
 
 // export const Handless = {
 //   entity: {
@@ -31,7 +32,9 @@ export const EntityRFPill = React.memo(({ data }: { data: any }) => {
 
   return (
     <div
-      className={styles.entity}
+      className={cn(styles.entity, {
+        [styles.highlighted]: data.suggestedForConnection,
+      })}
       style={{
         background: theme.palette.queryBuilder.entity.background,
         color: theme.palette.queryBuilder.text,
diff --git a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.module.scss b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.module.scss
index c0b913a4537276fa249d66b21fb846fc6fd18635..aff84b2e5d8b9caba6dd9fdd34a99b54614946d4 100644
--- a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.module.scss
+++ b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.module.scss
@@ -7,12 +7,17 @@
   background-color: transparent;
 }
 
+.highlighted {
+  box-shadow: black 0 0 2px;
+}
+
 .contentWrapper {
   display: flex;
   align-items: center;
 
   .handleLeft {
     position: relative;
+    z-index: 3;
 
     top: 25%;
     border: 0px;
@@ -86,6 +91,7 @@
 
 $height: 10px;
 .arrowLeft {
+  z-index: 2;
   width: 0;
   height: 0;
   border-top: $height solid transparent;
diff --git a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.tsx b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.tsx
index 34c0d57eb52dbddd0412474b2c765f321a0c1c8f..f1d4d8592cf367e719ac3db963948b5c06145ef1 100644
--- a/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.tsx
+++ b/apps/web-graphpolaris/src/components/querybuilder/customFlowPills/relationpill/relationpill.tsx
@@ -1,6 +1,7 @@
 import { handles } from '@graphpolaris/querybuilder/usecases';
 import { useTheme } from '@mui/material';
 import { Handle, Position } from 'react-flow-renderer';
+import cn from 'classnames';
 
 import styles from './relationpill.module.scss';
 
@@ -54,7 +55,9 @@ export default function RelationRFPill({ data }: { data: any }) {
         }}
       />
       <div
-        className={styles.contentWrapper}
+        className={cn(styles.contentWrapper, {
+          [styles.highlighted]: data.suggestedForConnection,
+        })}
         style={{
           color: theme.palette.queryBuilder.text,
           background: theme.palette.queryBuilder.relation.background,
diff --git a/apps/web-graphpolaris/src/components/querybuilder/querybuilder.tsx b/apps/web-graphpolaris/src/components/querybuilder/querybuilder.tsx
index 22a655d556152fb7281b0bb22908bb8c0f78e0a9..3870f76de645a2d47757c5e0a40e2c8bea89503b 100644
--- a/apps/web-graphpolaris/src/components/querybuilder/querybuilder.tsx
+++ b/apps/web-graphpolaris/src/components/querybuilder/querybuilder.tsx
@@ -1,14 +1,15 @@
 import {
   createReactFlowElements,
-  DragAttributePill,
-  DragAttributesAlong,
+  dragPill,
+  dragPillStarted,
+  dragPillStopped,
 } from '@graphpolaris/querybuilder/usecases';
 import {
   setQuerybuilderNodes,
   useAppDispatch,
   useQuerybuilderNodes,
 } from '@graphpolaris/shared/data-access/store';
-import { useMemo } from 'react';
+import { useMemo, useRef } from 'react';
 import ReactFlow, {
   ReactFlowProvider,
   Background,
@@ -38,6 +39,7 @@ const onLoad = (reactFlowInstance: any) => {
 const QueryBuilder = (props: {}) => {
   const nodes = useQuerybuilderNodes();
   const dispatch = useAppDispatch();
+  const isDraggingPill = useRef(false);
 
   const elements = useMemo(() => createReactFlowElements(nodes), [nodes]);
 
@@ -45,27 +47,35 @@ const QueryBuilder = (props: {}) => {
     event: React.MouseEvent<Element, MouseEvent>,
     node: Node<any>
   ) => {
+    // Get the node in the elements list to get the previous location
     const pNode = elements.find((e) => e.id == node.id);
     if (!(pNode && isNode(pNode))) return;
-
+    // This is then used to calculate the delta position
     const dx = node.position.x - pNode.position.x;
     const dy = node.position.y - pNode.position.y;
 
-    nodes.setNodeAttribute(node.id, 'x', node.position.x);
-    nodes.setNodeAttribute(node.id, 'y', node.position.y);
-
-    switch (nodes.getNodeAttribute(node.id, 'type')) {
-      case 'attribute':
-        DragAttributePill(node.id, nodes, dx, dy);
-        break;
-      case 'entity':
-        DragAttributesAlong(node.id, nodes, dx, dy);
-        break;
-      case 'relation':
-        DragAttributesAlong(node.id, nodes, dx, dy);
-        break;
+    // Check if we started dragging, if so, call the drag started usecase
+    if (!isDraggingPill.current) {
+      dragPillStarted(node.id, nodes);
+      isDraggingPill.current = true;
     }
 
+    // Call the drag usecase
+    dragPill(node.id, nodes, dx, dy, node.position);
+
+    // Dispatch the new graphology object, so reactflow will get rerendered
+    dispatch(setQuerybuilderNodes(nodes.export()));
+  };
+  const onNodeDragStop = (
+    event: React.MouseEvent<Element, MouseEvent>,
+    node: Node<any>
+  ) => {
+    isDraggingPill.current = false;
+
+    // Call the drag pill stopped usecase
+    dragPillStopped(node.id, nodes);
+
+    // Dispatch the new graphology object, so reactflow will get rerendered
     dispatch(setQuerybuilderNodes(nodes.export()));
   };
 
@@ -81,6 +91,7 @@ const QueryBuilder = (props: {}) => {
           connectionLineComponent={ConnectionDragLine}
           onLoad={onLoad}
           onNodeDrag={onNodeDrag}
+          onNodeDragStop={onNodeDragStop}
           className={styles.reactflow}
         >
           <Background gap={10} size={0.7} />
diff --git a/deployment.yml b/deployment.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fc945c18719db08baaf0e539fd9a16bcecb04609
--- /dev/null
+++ b/deployment.yml
@@ -0,0 +1,35 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: frontend-webserver-deployment
+  labels:
+    app: frontend-webserver
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: frontend-webserver
+  template:
+    metadata:
+      labels:
+        app: frontend-webserver
+    spec:
+      containers:
+        - name: container
+          image: datastropheregistry.azurecr.io/frontend:latest
+          ports:
+            - containerPort: 3000
+      imagePullSecrets:
+        - name: docker-regcred
+
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: frontend-webserver
+spec:
+  selector:
+    app: frontend-webserver
+  ports:
+    - port: 3000
+      targetPort: 80
diff --git a/libs/querybuilder/usecases/src/index.ts b/libs/querybuilder/usecases/src/index.ts
index fa59d4c1fd04854d57f7c8765d39de8a765054b9..32e0c81f2ecfe335cb61852728753c148b9c6c8b 100644
--- a/libs/querybuilder/usecases/src/index.ts
+++ b/libs/querybuilder/usecases/src/index.ts
@@ -2,6 +2,5 @@ export * from './lib/attribute/getAttributeBoolOperators';
 export * from './lib/attribute/checkInput';
 export * from './lib/createReactFlowElements';
 export * from './lib/pillHandles';
-export * from './lib/dragging/dragAttribute';
-export * from './lib/dragging/dragAttributesAlong';
+export * from './lib/dragging/dragPill';
 export * from './lib/addPill';
diff --git a/libs/querybuilder/usecases/src/lib/addPill.ts b/libs/querybuilder/usecases/src/lib/addPill.ts
index 008127598cfee48f3f71793ba23a5e3062607621..e7b359d8f0fc77f1281fa57a7c200f13acfb820e 100644
--- a/libs/querybuilder/usecases/src/lib/addPill.ts
+++ b/libs/querybuilder/usecases/src/lib/addPill.ts
@@ -56,7 +56,7 @@ function calcWidthHeightOfPill(attributes: Attributes): {
 
       const widthOfPillWithoutText = 42.1164; // WARNING: depends on styling
       w += widthOfPillWithoutText;
-      h = 21;
+      h = 20;
       break;
     }
     case 'relation': {
diff --git a/libs/querybuilder/usecases/src/lib/attribute/checkInput.ts b/libs/querybuilder/usecases/src/lib/attribute/checkInput.ts
index f48dd787c36ab5b8ceb4c2cdf24f9a8ba1c9d5a6..a1c29ab1f05d62105afaf80faaa405c30ce60535 100644
--- a/libs/querybuilder/usecases/src/lib/attribute/checkInput.ts
+++ b/libs/querybuilder/usecases/src/lib/attribute/checkInput.ts
@@ -11,7 +11,7 @@ function toBoolean(s: string): string {
   return 'false';
 }
 
-/** Checks if the provided value is the same as the datatype of the attribute. */
+/** Checks if the provided value has the same as the datatype of the attribute. */
 export function CheckDatatypeConstraint(type: string, str: string): string {
   let res = '';
   switch (type) {
diff --git a/libs/querybuilder/usecases/src/lib/createReactFlowElements.ts b/libs/querybuilder/usecases/src/lib/createReactFlowElements.ts
index eea786d7fe5c6cd7f3888545af8b621e6b69fbfc..eba3bf06477f9bd53ac9e1c87ea13126ecd58e02 100644
--- a/libs/querybuilder/usecases/src/lib/createReactFlowElements.ts
+++ b/libs/querybuilder/usecases/src/lib/createReactFlowElements.ts
@@ -1,6 +1,6 @@
-import Graph from 'graphology';
+import Graph, { MultiGraph } from 'graphology';
 import { Attributes } from 'graphology-types';
-import { Elements, Node, Edge } from 'react-flow-renderer';
+import { Elements, Node, Edge, XYPosition } from 'react-flow-renderer';
 
 // Takes the querybuilder graph as an input and creates react flow elements for them.
 export function createReactFlowElements(graph: Graph): Elements<Node | Edge> {
@@ -8,6 +8,7 @@ export function createReactFlowElements(graph: Graph): Elements<Node | Edge> {
 
   graph.forEachNode((node: string, attributes: Attributes): void => {
     let data;
+    let position = { x: attributes?.x || 0, y: attributes?.y || 0 };
 
     switch (attributes.type) {
       case 'entity':
@@ -41,21 +42,29 @@ export function createReactFlowElements(graph: Graph): Elements<Node | Edge> {
           value: attributes.value,
           attributeOfA: attributeOfA,
         };
+        // Get the position of the attribute, based on the connection to entity or relation
+        const p = getAttributePosition(node, graph);
+        if (p) position = p;
         break;
       }
     }
     // Each pill should have a name and type
-    data = { ...data, name: attributes.name };
+    data = {
+      ...data,
+      name: attributes.name,
+      suggestedForConnection: attributes.suggestedForConnection, // Highlights the pill, with shadow or something
+    };
 
     const RFNode: Node = {
       id: node,
       type: attributes.type,
-      position: { x: attributes?.x || 0, y: attributes?.y || 0 },
+      position: position,
       data: data,
     };
     elements.push(RFNode);
   });
 
+  // Add the reactflow edges
   graph.forEachEdge((edge, attributes, source, target): void => {
     // connection from attributes don't have visible connection lines
     if (attributes.type == 'attribute_connection') return;
@@ -73,3 +82,49 @@ export function createReactFlowElements(graph: Graph): Elements<Node | Edge> {
 
   return elements;
 }
+
+/** Gets the position of an attribute based on the connection to an entity or relation.
+ * It uses the position of the parent pill and what the index is of this attribute in all
+ * the connected attributes to the parent.
+ */
+function getAttributePosition(
+  id: string,
+  nodes: MultiGraph
+): XYPosition | undefined {
+  const nbs = nodes.filterOutNeighbors(id, (_, { type }) =>
+    ['entity', 'relation'].includes(type)
+  );
+
+  if (nbs.length > 1)
+    console.log(
+      'WARNING: attribute connected to  more than one entity or relation'
+    );
+  else if (nbs.length == 1) {
+    const nb = nbs[0];
+    const connectedAttributes = nodes.filterInNeighbors(
+      nb,
+      (_, { type }) => type == 'attribute'
+    );
+
+    // An entity can have more attributes, what is the attributes index in the attributes array of that entity?
+    let nthAttibute = -1;
+    for (let i = 0; i < connectedAttributes.length; i++) {
+      if (connectedAttributes[i] == id) {
+        nthAttibute = i;
+        break;
+      }
+    }
+
+    const nbAttr = nodes.getNodeAttributes(nb);
+
+    const pos = { x: nbAttr.x + 30, y: nbAttr.y + nbAttr.h };
+    // ASSUMES THAT EACH ATTRIBUTE HAS THE SAME HEIGHT
+    const heightOfAttributes = nodes.getNodeAttribute(id, 'h') - 1;
+    pos.y += nthAttibute * heightOfAttributes;
+
+    return pos;
+  }
+
+  // If the attribute has no (attribute_)connection, don't position it.
+  return undefined;
+}
diff --git a/libs/querybuilder/usecases/src/lib/dragging/dragAttribute.ts b/libs/querybuilder/usecases/src/lib/dragging/dragAttribute.ts
index 332ca29cd3283c97d3876b9ca176068d97815e3e..df89ab57dcc526b42c151e868a50add049efbe7d 100644
--- a/libs/querybuilder/usecases/src/lib/dragging/dragAttribute.ts
+++ b/libs/querybuilder/usecases/src/lib/dragging/dragAttribute.ts
@@ -1,12 +1,30 @@
-import Graph from 'graphology';
+import { MultiGraph } from 'graphology';
+import { GetClosestPill } from './getClosestPill';
+
+export function DragAttributePillStarted(id: string, nodes: MultiGraph) {
+  // if the attribute is still connected to an entity or relation pill, disconnect
+  const es = nodes.outEdges(id);
+  es.forEach((e) => nodes.dropEdge(e));
+}
 
 export function DragAttributePill(
   id: string,
-  nodes: Graph,
+  nodes: MultiGraph,
   dx: number,
   dy: number
 ) {
-  // if the attribute is still connected to an entity or relation pill, disconnect
-  const es = nodes.outEdges(id);
-  es.forEach((e) => nodes.dropEdge(e));
+  // Get the closes entity or relation node
+  const closestNode = GetClosestPill(id, nodes, ['entity', 'relation']);
+  // If we found one, highlight it by adding an attribute
+  if (closestNode)
+    nodes.setNodeAttribute(closestNode, 'suggestedForConnection', true);
+}
+
+export function DragAttibutePillStopped(id: string, nodes: MultiGraph) {
+  // If there is currently a node with the suggestedForConnection attribute
+  // connect this attribute to it
+  nodes.forEachNode((node, { suggestedForConnection }) => {
+    if (suggestedForConnection)
+      nodes.addEdge(id, node, { type: 'attribute_connection' });
+  });
 }
diff --git a/libs/querybuilder/usecases/src/lib/dragging/dragEntity.ts b/libs/querybuilder/usecases/src/lib/dragging/dragEntity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..171124ac9330a007b531311fec85dceeb4ccf945
--- /dev/null
+++ b/libs/querybuilder/usecases/src/lib/dragging/dragEntity.ts
@@ -0,0 +1,18 @@
+import { MultiGraph } from 'graphology';
+
+export function DragEntityPillStarted(id: string, nodes: MultiGraph) {
+  // Started dragging entity usecase
+}
+
+export function DragEntityPill(
+  id: string,
+  nodes: MultiGraph,
+  dx: number,
+  dy: number
+) {
+  // Code for dragging an entity pill should go here
+}
+
+export function DragEntityPillStopped(id: string, nodes: MultiGraph) {
+  // Stopped dragging entity pill
+}
diff --git a/libs/querybuilder/usecases/src/lib/dragging/dragPill.ts b/libs/querybuilder/usecases/src/lib/dragging/dragPill.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3832c103d94fbb2d759edc082cd643051580712a
--- /dev/null
+++ b/libs/querybuilder/usecases/src/lib/dragging/dragPill.ts
@@ -0,0 +1,90 @@
+import { MultiGraph } from 'graphology';
+import { XYPosition } from 'react-flow-renderer';
+import {
+  DragAttibutePillStopped,
+  DragAttributePill,
+  DragAttributePillStarted,
+} from './dragAttribute';
+import { DragAttributesAlong } from './dragAttributesAlong';
+import {
+  DragEntityPill,
+  DragEntityPillStarted,
+  DragEntityPillStopped,
+} from './dragEntity';
+import {
+  DragRelationPill,
+  DragRelationPillStarted,
+  DragRelationPillStopped,
+} from './dragRelation';
+
+export function dragPillStarted(id: string, nodes: MultiGraph) {
+  switch (nodes.getNodeAttribute(id, 'type')) {
+    case 'attribute':
+      DragAttributePillStarted(id, nodes);
+      break;
+    case 'entity':
+      DragEntityPillStarted(id, nodes);
+      break;
+    case 'relation':
+      DragRelationPillStarted(id, nodes);
+      break;
+  }
+}
+
+/**
+ * A general drag usecase for any pill, it will select the correct usecase for each pill
+ * @param id
+ * @param nodes The graphology query builder nodes object
+ * @param dx Delta x
+ * @param dy Delta y
+ * @param position The already updated positiong (dx dy are already applied)
+ */
+export function dragPill(
+  id: string,
+  nodes: MultiGraph,
+  dx: number,
+  dy: number,
+  position: XYPosition
+) {
+  // Update the position of the node in the graphology object
+  nodes.setNodeAttribute(id, 'x', position.x);
+  nodes.setNodeAttribute(id, 'y', position.y);
+
+  // Remove the highlighted attribute from each node
+  nodes.forEachNode((node) =>
+    nodes.removeNodeAttribute(node, 'suggestedForConnection')
+  );
+
+  switch (nodes.getNodeAttribute(id, 'type')) {
+    case 'attribute':
+      DragAttributePill(id, nodes, dx, dy);
+      break;
+    case 'entity':
+      DragAttributesAlong(id, nodes, dx, dy);
+      DragEntityPill(id, nodes, dx, dy);
+      break;
+    case 'relation':
+      DragAttributesAlong(id, nodes, dx, dy);
+      DragRelationPill(id, nodes, dx, dy);
+      break;
+  }
+}
+
+export function dragPillStopped(id: string, nodes: MultiGraph) {
+  switch (nodes.getNodeAttribute(id, 'type')) {
+    case 'attribute':
+      DragAttibutePillStopped(id, nodes);
+      break;
+    case 'entity':
+      DragEntityPillStopped(id, nodes);
+      break;
+    case 'relation':
+      DragRelationPillStopped(id, nodes);
+      break;
+  }
+
+  // Remove all suggestedForConnection attributes
+  nodes.forEachNode((node) =>
+    nodes.removeNodeAttribute(node, 'suggestedForConnection')
+  );
+}
diff --git a/libs/querybuilder/usecases/src/lib/dragging/dragRelation.ts b/libs/querybuilder/usecases/src/lib/dragging/dragRelation.ts
new file mode 100644
index 0000000000000000000000000000000000000000..12bf51961ae8cff27113c73a14c81d1e6c346b91
--- /dev/null
+++ b/libs/querybuilder/usecases/src/lib/dragging/dragRelation.ts
@@ -0,0 +1,18 @@
+import { MultiGraph } from 'graphology';
+
+export function DragRelationPillStarted(id: string, nodes: MultiGraph) {
+  // Started dragging relation usecase
+}
+
+export function DragRelationPill(
+  id: string,
+  nodes: MultiGraph,
+  dx: number,
+  dy: number
+) {
+  // Code for dragging an relation pill should go here
+}
+
+export function DragRelationPillStopped(id: string, nodes: MultiGraph) {
+  // Stopped dragging relation pill
+}
diff --git a/libs/querybuilder/usecases/src/lib/dragging/getClosestPill.ts b/libs/querybuilder/usecases/src/lib/dragging/getClosestPill.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0a3fd44874fa8de1f5b3d1508d456dfae0848faa
--- /dev/null
+++ b/libs/querybuilder/usecases/src/lib/dragging/getClosestPill.ts
@@ -0,0 +1,40 @@
+import { MultiGraph } from 'graphology';
+
+/**
+ * Gets the closest node to id
+ * @param id
+ * @param nodes Graphology querybuilder MultiGraph object
+ * @param allowedNodeTypes An array of the node types which are included in the search
+ * @param maxDistance The maximum distance
+ * @returns the closest node if within range
+ */
+export function GetClosestPill(
+  id: string,
+  nodes: MultiGraph,
+  allowedNodeTypes: string[],
+  maxDistance = 150
+): string | undefined {
+  const { x, y, w, h } = nodes.getNodeAttributes(id);
+  const center: { x: number; y: number } = { x: x + w / 2, y: y + h / 2 };
+
+  let minDist = maxDistance * maxDistance;
+  let closestNode: string | undefined = undefined;
+  nodes.forEachNode((node, { x, y, w, h, type }) => {
+    if (allowedNodeTypes.includes(type)) {
+      const nodeCenter: { x: number; y: number } = {
+        x: x + w / 2,
+        y: y + h / 2,
+      };
+
+      const dx = center.x - nodeCenter.x;
+      const dy = center.y - nodeCenter.y;
+      const dist = dx * dx + dy * dy;
+      if (dist < minDist) {
+        minDist = dist;
+        closestNode = node;
+      }
+    }
+  });
+
+  return closestNode;
+}
diff --git a/libs/shared/data-access/api/src/lib/database.ts b/libs/shared/data-access/api/src/lib/database.ts
index 8d6700de6f55dde670227d1cedf1080c44637e28..da706c42a71c1cedc8a777afd5870480b3ec17eb 100644
--- a/libs/shared/data-access/api/src/lib/database.ts
+++ b/libs/shared/data-access/api/src/lib/database.ts
@@ -14,7 +14,7 @@ export type AddDatabaseRequest = {
 
 export function AddDatabase(request: AddDatabaseRequest): Promise<void> {
   return new Promise((resolve, reject) => {
-    fetch('https://datastrophe.science.uu.nl/user/database', {
+    fetch('https://api.graphpolaris.com/user/database', {
       method: 'POST',
       credentials: 'same-origin',
       headers: new Headers({
@@ -34,7 +34,7 @@ export function AddDatabase(request: AddDatabaseRequest): Promise<void> {
 
 export function GetAllDatabases(): Promise<Array<string>> {
   return new Promise<Array<string>>((resolve, reject) => {
-    fetch('https://datastrophe.science.uu.nl/user/database', {
+    fetch('https://api.graphpolaris.com/user/database', {
       method: 'GET',
       credentials: 'same-origin',
       headers: new Headers({
@@ -57,7 +57,7 @@ export function GetAllDatabases(): Promise<Array<string>> {
 
 export function DeleteDatabase(name: string): Promise<void> {
   return new Promise((resolve, reject) => {
-    fetch('https://datastrophe.science.uu.nl/user/database/' + name, {
+    fetch('https://api.graphpolaris.com/user/database/' + name, {
       method: 'DELETE',
       credentials: 'same-origin',
       headers: new Headers({
diff --git a/libs/shared/data-access/api/src/lib/user.ts b/libs/shared/data-access/api/src/lib/user.ts
index 457ce20f6af6c8be31727f2b9757134827b4fc70..b3d7b3fc9e6b5411369a4a5b11e3ed8e7e009065 100644
--- a/libs/shared/data-access/api/src/lib/user.ts
+++ b/libs/shared/data-access/api/src/lib/user.ts
@@ -10,7 +10,7 @@ export type User = {
 
 export function GetUserInfo(): Promise<User> {
   return new Promise<User>((resolve, reject) => {
-    fetch('https://datastrophe.science.uu.nl/user/', {
+    fetch('https://api.graphpolaris.com/user/', {
       method: 'GET',
       credentials: 'same-origin',
       headers: new Headers({
diff --git a/libs/shared/data-access/authorization/src/lib/authorizationHandler.ts b/libs/shared/data-access/authorization/src/lib/authorizationHandler.ts
index fc92922419ad609e85767e55dd35b06b2a581012..bc6001fd2aed8d24d60abf15411167af64629e81 100644
--- a/libs/shared/data-access/authorization/src/lib/authorizationHandler.ts
+++ b/libs/shared/data-access/authorization/src/lib/authorizationHandler.ts
@@ -1,5 +1,3 @@
-import { Cookies } from 'react-cookie';
-
 export class AuthorizationHandler {
   private static _instance: AuthorizationHandler;
   private accessToken = '';
@@ -52,7 +50,7 @@ export class AuthorizationHandler {
    */
   private async getNewAccessToken(): Promise<authResponse> {
     // If we have an access token already, append it to the url as a query param to keep sessionID the same
-    let url = 'https://datastrophe.science.uu.nl/auth/refresh';
+    let url = 'https://api.graphpolaris.com/auth/refresh';
     if (this.accessToken != '') {
       url += '?access_token=' + this.accessToken;
     }
@@ -104,7 +102,7 @@ export class AuthorizationHandler {
    * initialiseRefreshToken attempts to initialise a refresh token
    */
   private async initialiseRefreshToken() {
-    fetch('https://datastrophe.science.uu.nl/auth/refresh', {
+    fetch('https://api.graphpolaris.com/auth/refresh', {
       method: 'POST',
       credentials: 'include',
     })
diff --git a/libs/shared/models/yarn.lock b/libs/shared/models/yarn.lock
new file mode 100644
index 0000000000000000000000000000000000000000..fb57ccd13afbd082ad82051c2ffebef4840661ec
--- /dev/null
+++ b/libs/shared/models/yarn.lock
@@ -0,0 +1,4 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
diff --git a/libs/shared/schema-utils/yarn.lock b/libs/shared/schema-utils/yarn.lock
new file mode 100644
index 0000000000000000000000000000000000000000..fb57ccd13afbd082ad82051c2ffebef4840661ec
--- /dev/null
+++ b/libs/shared/schema-utils/yarn.lock
@@ -0,0 +1,4 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
diff --git a/nginx/nginx.conf b/nginx/nginx.conf
new file mode 100644
index 0000000000000000000000000000000000000000..ef2e21a890fc402b46472b5c18fd5b95c3a53a2e
--- /dev/null
+++ b/nginx/nginx.conf
@@ -0,0 +1,16 @@
+server {
+  listen 80;
+
+  location / {
+    root   /usr/share/nginx/html;
+    index  index.html index.htm;
+    try_files $uri $uri/ /index.html;
+  }
+
+  error_page 500 502 503 504 /50x.html;
+
+  location = /50x.html {
+      root /usr/share/nginx/html;
+  }
+
+}
diff --git a/package.json b/package.json
index 3f7093bb5c59beccce637d66aefbbab914cb7188..9d07a7788766fc39c5af14ad5142bf853f2776fe 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
     "@types/cytoscape": "^3.19.4",
     "@types/react-grid-layout": "^1.3.0",
     "@types/styled-components": "^5.1.21",
+    "classnames": "^2.3.1",
     "color": "^4.2.1",
     "core-js": "^3.6.5",
     "cytoscape": "^3.21.0",
diff --git a/yarn.lock b/yarn.lock
index 39285815c8ccda88216897b21a703f99843949e0..ad3e6305a7719eb8dc8d0e2a9ad48f4ff0bc32e8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6427,6 +6427,11 @@ classcat@^5.0.3:
   resolved "https://registry.yarnpkg.com/classcat/-/classcat-5.0.3.tgz#38eaa0ec6eb1b10faf101bbcef2afb319c23c17b"
   integrity sha512-6dK2ke4VEJZOFx2ZfdDAl5OhEL8lvkl6EHF92IfRePfHxQTqir5NlcNVUv+2idjDqCX2NDc8m8YSAI5NI975ZQ==
 
+classnames@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
+  integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
+
 clean-css@^4.2.3:
   version "4.2.4"
   resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178"