diff --git a/docker-compose.yml b/docker-compose.yml
index f64dd18c7358bda9ee5b8b5bf21c7a63138b07dd..31504d4638e5f88aebb69d29e1f33a92e699c023 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -4,7 +4,7 @@ services:
     build: .
     container_name: back
     ports:
-      - 8080:5000
+      - 5000:5000
   postgres:
     image: mdillon/postgis
     container_name: postgis
diff --git a/ormconfig.json.example b/ormconfig.json.example
index e5a401dd8792446e8202058b594684ad44a86d6b..78ed436feede989d81d044795a41227e73e3f94a 100644
--- a/ormconfig.json.example
+++ b/ormconfig.json.example
@@ -1,12 +1,12 @@
-
 {
-    "type": "",
-    "host": "",
-    "port": ,
-    "username": "",
-    "password": "",
-    "database": "",
-    "entities": ["src/**/*.entity{.ts,.js}"],
-    "synchronize": true,
-    "logging": true
-  }
\ No newline at end of file
+  "type": "postgres",
+  "host": "localhost",
+  "port": 5432,
+  "username": "ehasa",
+  "password": "salasana",
+  "database": "ehasa",
+  "entities": ["src/**/*.entity{.ts,.js}"],
+  "synchronize": true,
+  "logging": true,
+  "dropSchema": true
+}
diff --git a/package-lock.json b/package-lock.json
index 53a606c27128a913a5a331e85d089988f9f164f0..be2f7c8964168262bdeaafcfad35ef0656a2656e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1450,11 +1450,6 @@
       "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
       "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
     },
-    "bluebird": {
-      "version": "3.5.5",
-      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
-      "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w=="
-    },
     "body-parser": {
       "version": "1.19.0",
       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
@@ -1906,15 +1901,6 @@
         "wrap-ansi": "^2.0.0"
       }
     },
-    "cls-bluebird": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz",
-      "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=",
-      "requires": {
-        "is-bluebird": "^1.0.2",
-        "shimmer": "^1.1.0"
-      }
-    },
     "co": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -2397,11 +2383,6 @@
       "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz",
       "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w=="
     },
-    "dottie": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.1.tgz",
-      "integrity": "sha512-ch5OQgvGDK2u8pSZeSYAQaV/lczImd7pMJ7BcEPXmnFVjy4yJIzP6CsODJUTH8mg1tyH1Z2abOiuJO3DjZ/GBw=="
-    },
     "double-ended-queue": {
       "version": "2.1.0-0",
       "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz",
@@ -3125,8 +3106,7 @@
         "ansi-regex": {
           "version": "2.1.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -3147,14 +3127,12 @@
         "balanced-match": {
           "version": "1.0.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -3169,20 +3147,17 @@
         "code-point-at": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "concat-map": {
           "version": "0.0.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -3299,8 +3274,7 @@
         "inherits": {
           "version": "2.0.3",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "ini": {
           "version": "1.3.5",
@@ -3312,7 +3286,6 @@
           "version": "1.0.0",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -3327,7 +3300,6 @@
           "version": "3.0.4",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -3335,14 +3307,12 @@
         "minimist": {
           "version": "0.0.8",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "minipass": {
           "version": "2.3.5",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.2",
             "yallist": "^3.0.0"
@@ -3361,7 +3331,6 @@
           "version": "0.5.1",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -3442,8 +3411,7 @@
         "number-is-nan": {
           "version": "1.0.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "object-assign": {
           "version": "4.1.1",
@@ -3455,7 +3423,6 @@
           "version": "1.4.0",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -3541,8 +3508,7 @@
         "safe-buffer": {
           "version": "5.1.2",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -3578,7 +3544,6 @@
           "version": "1.0.2",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
@@ -3598,7 +3563,6 @@
           "version": "3.0.1",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -3642,14 +3606,12 @@
         "wrappy": {
           "version": "1.0.2",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "yallist": {
           "version": "3.0.3",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         }
       }
     },
@@ -4020,11 +3982,6 @@
       "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
       "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
     },
-    "inflection": {
-      "version": "1.12.0",
-      "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz",
-      "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY="
-    },
     "inflight": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -4088,11 +4045,6 @@
         "binary-extensions": "^1.0.0"
       }
     },
-    "is-bluebird": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz",
-      "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI="
-    },
     "is-buffer": {
       "version": "1.1.6",
       "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
@@ -5145,7 +5097,8 @@
     "lodash": {
       "version": "4.17.11",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+      "dev": true
     },
     "lodash.includes": {
       "version": "4.3.0",
@@ -5443,19 +5396,6 @@
         "minimist": "0.0.8"
       }
     },
-    "moment": {
-      "version": "2.24.0",
-      "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
-      "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
-    },
-    "moment-timezone": {
-      "version": "0.5.25",
-      "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.25.tgz",
-      "integrity": "sha512-DgEaTyN/z0HFaVcVbSyVCUU6HeFdnNC3vE4c9cgu2dgMTvjBUBdBzWfasTBmAW45u5OIMeCJtU8yNjM22DHucw==",
-      "requires": {
-        "moment": ">= 2.9.0"
-      }
-    },
     "ms": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
@@ -6553,14 +6493,6 @@
       "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
       "dev": true
     },
-    "retry-as-promised": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz",
-      "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==",
-      "requires": {
-        "any-promise": "^1.3.0"
-      }
-    },
     "rimraf": {
       "version": "2.6.3",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
@@ -6689,51 +6621,6 @@
         }
       }
     },
-    "sequelize": {
-      "version": "5.8.7",
-      "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.8.7.tgz",
-      "integrity": "sha512-1rubZM8fAyCt5ipyS+3HJ3Jbmb8WesLdPJ3jIbTD+78EbuPZILFEA5fK0mliVRBx7oM7oPULeVX0lxSRXBV1jw==",
-      "requires": {
-        "bluebird": "^3.5.0",
-        "cls-bluebird": "^2.1.0",
-        "debug": "^4.1.1",
-        "dottie": "^2.0.0",
-        "inflection": "1.12.0",
-        "lodash": "^4.17.11",
-        "moment": "^2.24.0",
-        "moment-timezone": "^0.5.21",
-        "retry-as-promised": "^3.1.0",
-        "semver": "^5.6.0",
-        "sequelize-pool": "^1.0.2",
-        "toposort-class": "^1.0.1",
-        "uuid": "^3.2.1",
-        "validator": "^10.11.0",
-        "wkx": "^0.4.6"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "validator": {
-          "version": "10.11.0",
-          "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz",
-          "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw=="
-        }
-      }
-    },
-    "sequelize-pool": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-1.0.2.tgz",
-      "integrity": "sha512-VMKl/gCCdIvB1gFZ7p+oqLFEyZEz3oMMYjkKvfEC7GoO9bBcxmfOOU9RdkoltfXGgBZFigSChihRly2gKtsh2w==",
-      "requires": {
-        "bluebird": "^3.5.3"
-      }
-    },
     "serve-static": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
@@ -6797,11 +6684,6 @@
       "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
       "dev": true
     },
-    "shimmer": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz",
-      "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="
-    },
     "signal-exit": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
@@ -7555,11 +7437,6 @@
         }
       }
     },
-    "toposort-class": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz",
-      "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg="
-    },
     "touch": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
@@ -7885,9 +7762,9 @@
       }
     },
     "typescript": {
-      "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.3.tgz",
-      "integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==",
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz",
+      "integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==",
       "dev": true
     },
     "uglify-js": {
@@ -8256,14 +8133,6 @@
         "string-width": "^2.1.1"
       }
     },
-    "wkx": {
-      "version": "0.4.6",
-      "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.6.tgz",
-      "integrity": "sha512-LHxXlzRCYQXA9ZHgs8r7Gafh0gVOE8o3QmudM1PIkOdkXXjW7Thcl+gb2P2dRuKgW8cqkitCRZkkjtmWzpHi7A==",
-      "requires": {
-        "@types/node": "*"
-      }
-    },
     "wordwrap": {
       "version": "0.0.3",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
diff --git a/package.json b/package.json
index 9e44f929c2267e5ed2e143931c9b6a6bf908ff0e..794db7d353397154ef795d59135b5771df8300ff 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,6 @@
     "reflect-metadata": "^0.1.12",
     "rimraf": "^2.6.2",
     "rxjs": "^6.3.3",
-    "sequelize": "^5.8.7",
     "socket.io-redis": "^5.2.0",
     "typeorm": "^0.2.17"
   },
@@ -60,7 +59,7 @@
     "ts-node": "^8.3.0",
     "tsconfig-paths": "^3.8.0",
     "tslint": "5.16.0",
-    "typescript": "^3.4.3",
+    "typescript": "^3.5.2",
     "wait-on": "^3.2.0"
   },
   "jest": {
diff --git a/src/app.module.ts b/src/app.module.ts
index 91f8bcb4a12aad77ab1d506b941bf71f7278a2a6..f2c7b7765304436488bbadb3fdfce4fbdc1fbd9a 100644
--- a/src/app.module.ts
+++ b/src/app.module.ts
@@ -1,16 +1,24 @@
 import { Module } from '@nestjs/common';
 import { APP_FILTER, APP_INTERCEPTOR, APP_GUARD } from '@nestjs/core';
 import { TypeOrmModule } from '@nestjs/typeorm';
+import { Connection } from 'typeorm';
+
 import { AppController } from './app.controller';
 import { AppService } from './app.service';
-import { Connection } from 'typeorm';
-import { UserModule } from './user/user.module';
 
-import { HttpErrorFilter } from './shared/http-error.filter';
+import { RolesGuard } from './shared/roles.guard';
 import { LoggingInterceptor } from './shared/logging.interceptor';
+import { StatesGuard } from './shared/states.guard';
+import { HttpErrorFilter } from './shared/http-error.filter';
+
 import { NotificationModule } from './notifications/notifications.module';
+import { TaskModule } from './task/task.module';
+import { TrackingModule } from './tracking/tracking.module';
+import { UserModule } from './user/user.module';
+import { DrawModule } from './draw/draw.module';
+import { FactionModule } from './faction/faction.module';
 import { GameModule } from './game/game.module';
-import { RolesGuard } from './shared/roles.guard';
+import { ScoreModule } from './score/score.module';
 
 @Module({
   imports: [
@@ -18,6 +26,11 @@ import { RolesGuard } from './shared/roles.guard';
     UserModule,
     GameModule,
     NotificationModule,
+    TaskModule,
+    DrawModule,
+    FactionModule,
+    TrackingModule,
+    ScoreModule,
   ],
   controllers: [AppController],
   providers: [
@@ -34,6 +47,10 @@ import { RolesGuard } from './shared/roles.guard';
       provide: APP_GUARD,
       useClass: RolesGuard,
     },
+    {
+      provide: APP_GUARD,
+      useClass: StatesGuard,
+    },
   ],
 })
 export class AppModule {
diff --git a/src/draw/coordinate.entity.ts b/src/draw/coordinate.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ef5447f61cfd1dd07d1f81a8ee1fce8e8256da2a
--- /dev/null
+++ b/src/draw/coordinate.entity.ts
@@ -0,0 +1,51 @@
+import {
+  Entity,
+  Column,
+  PrimaryGeneratedColumn,
+  ManyToOne,
+  Timestamp,
+} from 'typeorm';
+
+import { Game_PersonEntity, GameEntity } from '../game/game.entity';
+import { FactionEntity } from '../faction/faction.entity';
+
+@Entity('MapDrawing')
+export class MapDrawingEntity {
+  @PrimaryGeneratedColumn('uuid') mapDrawingId: string;
+  @Column({ type: 'bool', nullable: true }) drawingIsActive: boolean;
+  @Column({ type: 'time', nullable: true }) drawingValidTill: string;
+
+  @Column({ type: 'json', nullable: true }) data: JSON;
+
+  @ManyToOne(type => FactionEntity, faction => faction.mapDrawings, {
+    onDelete: 'CASCADE',
+  })
+  faction: FactionEntity;
+  @ManyToOne(type => GameEntity, gameEntity => gameEntity.id, {
+    onDelete: 'CASCADE',
+  })
+  gameId: GameEntity;
+}
+
+@Entity('Game_Person_MapDrawing')
+export class Game_Person_MapDrawingEntity {
+  @PrimaryGeneratedColumn('uuid') GPmapDrawingId: string;
+  @Column({ type: 'timestamp' }) GPCTimeStamp: Timestamp;
+
+  @ManyToOne(
+    type => Game_PersonEntity,
+    game_person => game_person.gamepersonId,
+    {
+      onDelete: 'CASCADE',
+    },
+  )
+  game_person: Game_PersonEntity;
+  @ManyToOne(
+    type => MapDrawingEntity,
+    map_drawing => map_drawing.mapDrawingId,
+    {
+      onDelete: 'CASCADE',
+    },
+  )
+  map_drawing: MapDrawingEntity;
+}
diff --git a/src/draw/draw.controller.ts b/src/draw/draw.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..26f6cf8c56142ef190ad3bcbfd7ce9d32caa371e
--- /dev/null
+++ b/src/draw/draw.controller.ts
@@ -0,0 +1,42 @@
+import {
+  Controller,
+  Put,
+  UseGuards,
+  Get,
+  Param,
+  UsePipes,
+  ValidationPipe,
+  Body,
+} from '@nestjs/common';
+
+import { AuthGuard } from '../shared/auth.guard';
+import { DrawService } from './draw.service';
+import { Roles, GameStates } from '../shared/guard.decorator';
+import { MapDrawingDTO, ReturnDrawingsDTO } from './mapdrawing.dto';
+
+/*
+      DrawController
+  
+      Functions either insert or return MapDrawing data,
+      Insert functions require user to have proper role (either gm or commander) in the game to be able store the ddata: MapDrawingDTOata to database.
+      Data return functions require atleast spectator role.
+  */
+@Controller('draw')
+export class DrawController {
+  constructor(private drawService: DrawService) {}
+
+  @Put('mapdrawing/:id')
+  @Roles('admin', 'factionleader')
+  @GameStates('CREATED', 'STARTED')
+  @UsePipes(new ValidationPipe())
+  async draw(@Param('id') gameId, @Body() data: MapDrawingDTO) {
+    return this.drawService.draw(gameId, data);
+  }
+
+  @Get('map/:id')
+  @UseGuards(new AuthGuard())
+  @UsePipes(new ValidationPipe())
+  async drawMap(@Param('id') id, @Body() data: ReturnDrawingsDTO) {
+    return this.drawService.drawMap(id, data);
+  }
+}
diff --git a/src/draw/draw.module.ts b/src/draw/draw.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a56cbbbb7fb49b476842177a4a0a9e7e0b592b3c
--- /dev/null
+++ b/src/draw/draw.module.ts
@@ -0,0 +1,24 @@
+import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
+
+import { DrawController } from './draw.controller';
+import { DrawService } from './draw.service';
+import { MapDrawingEntity } from '../draw/coordinate.entity';
+import { FactionEntity } from '../faction/faction.entity';
+import { Game_PersonEntity } from '../game/game.entity';
+/*
+Draw
+- contains everything to do with mapdrawing data.
+*/
+@Module({
+  imports: [
+    TypeOrmModule.forFeature([
+      MapDrawingEntity,
+      FactionEntity,
+      Game_PersonEntity,
+    ]),
+  ],
+  controllers: [DrawController],
+  providers: [DrawService],
+})
+export class DrawModule {}
diff --git a/src/draw/draw.service.ts b/src/draw/draw.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d5ddf23e9574771bc769e2b6d58b59a4e95ad10d
--- /dev/null
+++ b/src/draw/draw.service.ts
@@ -0,0 +1,46 @@
+import { Injectable } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+
+import { MapDrawingEntity } from '../draw/coordinate.entity';
+import { MapDrawingDTO, ReturnDrawingsDTO } from './mapdrawing.dto';
+
+@Injectable()
+export class DrawService {
+  constructor(
+    @InjectRepository(MapDrawingEntity)
+    private mapDrawingRepository: Repository<MapDrawingEntity>,
+  ) {}
+
+  async draw(gameId, data: MapDrawingDTO) {
+    data['gameId'] = gameId;
+    const drawing = await this.mapDrawingRepository.create(data);
+    if (data.mapDrawingId == null || data.mapDrawingId == '') {
+      // luo uuden instanssin.
+      const mapDrawing = await this.mapDrawingRepository.insert(drawing);
+      return mapDrawing.identifiers;
+    } else {
+      //päivittää mapDrawingin
+      return await this.mapDrawingRepository.save(drawing);
+    }
+  }
+
+  // draw map based on game and
+  async drawMap(id, data: ReturnDrawingsDTO) {
+    // return mapdrawings with given faction and gameid
+    return await this.mapDrawingRepository.find({
+      where: [
+        {
+          gameId: id,
+          faction: data.factionId,
+          drawingIsActive: true,
+        },
+        {
+          gameId: id,
+          faction: null,
+          drawingIsActive: true,
+        },
+      ],
+    });
+  }
+}
diff --git a/src/draw/mapdrawing.dto.ts b/src/draw/mapdrawing.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f7e7c781a0cbd308edf5f8c14f068b449f43a05e
--- /dev/null
+++ b/src/draw/mapdrawing.dto.ts
@@ -0,0 +1,27 @@
+import { IsUUID, IsOptional, IsBoolean, Allow } from 'class-validator';
+
+import { FactionEntity } from '../faction/faction.entity';
+import { GameEntity } from '../game/game.entity';
+
+export class MapDrawingDTO {
+  @IsOptional()
+  @IsUUID('4')
+  mapDrawingId: string;
+  @Allow()
+  data: JSON;
+  @IsOptional()
+  @IsUUID('4')
+  gameId: GameEntity;
+  @IsOptional()
+  @IsUUID('4')
+  faction?: FactionEntity;
+  @IsBoolean()
+  drawingIsActive?: boolean;
+  drawingValidTill?: string;
+}
+
+export class ReturnDrawingsDTO {
+  @IsOptional()
+  @IsUUID('4')
+  factionId: FactionEntity;
+}
diff --git a/src/faction/faction.controller.ts b/src/faction/faction.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..da7e5950626bbcd5385d80755d208e59be589b48
--- /dev/null
+++ b/src/faction/faction.controller.ts
@@ -0,0 +1,98 @@
+import {
+  Controller,
+  Post,
+  UseGuards,
+  UsePipes,
+  Param,
+  Body,
+  Get,
+  Put,
+  UseInterceptors,
+  ClassSerializerInterceptor,
+} from '@nestjs/common';
+
+import { AuthGuard } from '../shared/auth.guard';
+import { ValidationPipe } from '../shared/validation.pipe';
+import { User } from '../user/user.decorator';
+import {
+  GameGroupDTO,
+  PromotePlayerDTO,
+  JoinFactionDTO,
+  JoinGameGroupDTO,
+} from './faction.dto';
+import { FactionService } from './faction.service';
+import { Roles, GameStates } from '../shared/guard.decorator';
+
+@Controller('faction')
+export class FactionController {
+  constructor(private factionservice: FactionService) {}
+
+  // takes gameId from the url to verify user role
+  @Post('create-group/:id')
+  @Roles('soldier')
+  @GameStates('CREATED')
+  @UsePipes(new ValidationPipe())
+  async createGroup(
+    @User('id') person,
+    @Param('id') id: string,
+    @Body() data: GameGroupDTO,
+  ) {
+    try {
+      return this.factionservice.createGroup(person, id, data);
+    } catch (error) {}
+  }
+
+  // id is faction ID
+  @Get('get-groups/:id')
+  async getGroups(@Param('id') id) {
+    return this.factionservice.showGroups(id);
+  }
+
+  // takes gameId from the url to verify user role
+  @Put('join-group/:id')
+  @Roles('soldier')
+  @GameStates('CREATED')
+  async joinGroup(
+    @User('id') person,
+    @Param('id') id,
+    @Body() data: JoinGameGroupDTO,
+  ) {
+    return this.factionservice.joinGroup(person, id, data);
+  }
+
+  @UseInterceptors(ClassSerializerInterceptor)
+  @Get('get-faction-members/:id')
+  async getFactionMembers(@Param('id') factionId) {
+    return this.factionservice.listFactionMembers(factionId);
+  }
+
+  // param game ID is passed to @Roles
+  @Put('promote/:id')
+  @Roles('admin')
+  @GameStates('CREATED')
+  @UsePipes(new ValidationPipe())
+  promotePlayer(@Param('id') game, @Body() body: PromotePlayerDTO) {
+    return this.factionservice.promotePlayer(body);
+  }
+
+  // used to join a faction
+  // :id is the id of the game, and is needed for GameStates to check the state of the game
+  @Put('join-faction/:id')
+  @UseGuards(new AuthGuard())
+  @GameStates('CREATED', 'STARTED')
+  @UsePipes(new ValidationPipe())
+  joinFaction(
+    @User('id') person,
+    @Param('id') game,
+    @Body() data: JoinFactionDTO,
+  ) {
+    return this.factionservice.joinFaction(person, data);
+  }
+
+  // check if person belongs to a faction in a game
+  @Get('check-faction/:id')
+  @UseGuards(new AuthGuard())
+  checkFaction(@User('id') userId, @Param('id') gameId) {
+    return this.factionservice.verifyUser(userId, gameId);
+  }
+}
diff --git a/src/faction/faction.dto.ts b/src/faction/faction.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0b65c47007d6424584d8fdb35ac9d9ee53eaa924
--- /dev/null
+++ b/src/faction/faction.dto.ts
@@ -0,0 +1,64 @@
+import {
+  IsUUID,
+  Length,
+  Validate,
+  IsString,
+  IsNotEmpty,
+  IsNumber,
+  Min,
+  Max,
+  IsOptional,
+} from 'class-validator';
+
+import { GameEntity } from '../game/game.entity';
+import { RoleValidation, Uuid } from '../shared/custom-validation';
+import { GameDTO } from '../game/game.dto';
+import { FactionEntity, GameGroupEntity } from './faction.entity';
+
+export class FactionDTO {
+  @IsOptional()
+  @IsUUID('4')
+  factionId?: string;
+  @IsString()
+  @IsNotEmpty()
+  @Length(2, 31)
+  factionName: string;
+  @IsString()
+  @IsNotEmpty()
+  @Length(3, 15)
+  factionPassword: string;
+  @IsNumber()
+  @Min(1)
+  @Max(3)
+  multiplier?: number;
+  game: GameDTO;
+}
+
+export class JoinFactionDTO {
+  @IsUUID('4')
+  factionId: string;
+  @Length(3, 31)
+  factionPassword: string;
+  @IsUUID('4')
+  game: GameEntity;
+}
+
+export class PromotePlayerDTO {
+  @IsUUID('4')
+  player: string;
+  @Validate(RoleValidation)
+  role: string;
+}
+
+export class GameGroupDTO {
+  @IsString()
+  @Length(3, 31)
+  name: string;
+  @IsUUID('4')
+  faction: FactionEntity;
+}
+
+export class JoinGameGroupDTO {
+  @IsUUID('4')
+  groupId: GameGroupEntity;
+}
diff --git a/src/game/faction.entity.ts b/src/faction/faction.entity.ts
similarity index 55%
rename from src/game/faction.entity.ts
rename to src/faction/faction.entity.ts
index 135d73a4108b3191e29c9e8921f1fbf5dffc9a37..3aa74cf615d77deb1421d52d46d4159bf7e0d241 100644
--- a/src/game/faction.entity.ts
+++ b/src/faction/faction.entity.ts
@@ -4,28 +4,48 @@ import {
   PrimaryGeneratedColumn,
   OneToMany,
   ManyToOne,
+  OneToOne,
   Timestamp,
+  JoinColumn,
 } from 'typeorm';
-import { GameEntity } from './game.entity';
-import { Game_PersonEntity } from './game.entity';
-import { MapDrawingEntity } from './coordinate.entity';
 
-//Faction, PowerUp, Faction_powerUp, FP_History, Score, Task
+import { GameEntity } from '../game/game.entity';
+import { Game_PersonEntity } from '../game/game.entity';
+import { MapDrawingEntity } from '../draw/coordinate.entity';
+import { Exclude } from 'class-transformer';
+
+//Faction, PowerUp, Faction_powerUp, FP_History, Score
 
 @Entity('Faction')
 export class FactionEntity {
   @PrimaryGeneratedColumn('uuid') factionId: string;
   @Column('text') factionName: string;
-  @Column({ type: 'text' }) factionPassword: string;
   @Column({ type: 'float' }) multiplier: number;
 
+  @Exclude()
+  @Column({ type: 'text' })
+  factionPassword: string;
+
   @OneToMany(type => Game_PersonEntity, game_persons => game_persons.faction)
   game_persons: Game_PersonEntity[];
-  @ManyToOne(type => GameEntity, game => game.id)
-  gameId: GameEntity;
+  @ManyToOne(type => GameEntity, game => game.factions, {
+    onDelete: 'CASCADE',
+  })
+  game: GameEntity;
+  @OneToMany(type => MapDrawingEntity, mapDrawings => mapDrawings.faction)
+  mapDrawings: MapDrawingEntity[];
+
+  factionObject() {
+    const { factionId, factionName, game } = this;
+    return { factionId, factionName, game };
+  }
+
+  passwordCheck(pass: string) {
+    return pass == this.factionPassword ? true : false;
+  }
 }
 
-@Entity('PowerUp')
+/* @Entity('PowerUp')
 export class PowerUpEntity {
   @PrimaryGeneratedColumn('uuid') powerUpId: string;
   @Column({ type: 'text' }) powerUpName: string;
@@ -33,7 +53,9 @@ export class PowerUpEntity {
   @Column({ type: 'int' }) amount: number;
   @Column({ type: 'time' }) cooldown: string;
 
-  @OneToMany(type => FactionEntity, factions => factions.factionId)
+  @OneToMany(type => FactionEntity, factions => factions.factionId, {
+    onDelete: 'CASCADE',
+  })
   factions: Faction_PowerUpEntity[];
 }
 
@@ -59,28 +81,23 @@ export class FP_HistoryEntity {
     faction_PowerUp => faction_PowerUp.histories,
   )
   faction_PowerUp: Faction_PowerUpEntity;
-}
-
-@Entity('Score')
-export class ScoreEntity {
-  @PrimaryGeneratedColumn('uuid') scoreId: string;
-  @Column({ type: 'float' }) score: number;
-  @Column({ type: 'timestamp' }) scoreTimeStamp: Timestamp;
+} */
 
-  @ManyToOne(type => FactionEntity, factionName => factionName.factionId)
-  faction: FactionEntity;
-}
-
-@Entity('Task')
-export class TaskEntity {
-  @PrimaryGeneratedColumn('uuid') taskId: string;
-  @Column({ type: 'text' }) taskName: string;
-  @Column({ type: 'text' }) taskDescription: string;
-  @Column({ type: 'text' }) taskWinner: string;
-  @Column({ type: 'bool' }) taskIsActive: boolean;
-
-  @ManyToOne(type => FactionEntity, faction => faction.factionId)
+@Entity('GameGroup')
+export class GameGroupEntity {
+  @PrimaryGeneratedColumn('uuid') id: string;
+  @Column('text') name: string;
+  @OneToOne(type => Game_PersonEntity, person => person.leaderGroup, {
+    onDelete: 'CASCADE',
+  })
+  @JoinColumn({ name: 'leader' })
+  leader: Game_PersonEntity;
+  @OneToMany(type => Game_PersonEntity, person => person.group, {
+    onDelete: 'CASCADE',
+  })
+  players: Game_PersonEntity[];
+  @ManyToOne(type => FactionEntity, faction => faction.factionId, {
+    onDelete: 'CASCADE',
+  })
   faction: FactionEntity;
-  /*     @ManyToOne(type => PersonEntity, person => person.tasks)
-    person: PersonEntity; */
 }
diff --git a/src/faction/faction.module.ts b/src/faction/faction.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dcb399aa1119851781270477c448ecec7362c804
--- /dev/null
+++ b/src/faction/faction.module.ts
@@ -0,0 +1,20 @@
+import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
+
+import { FactionController } from './faction.controller';
+import { FactionService } from './faction.service';
+import { GameGroupEntity, FactionEntity } from './faction.entity';
+import { Game_PersonEntity } from '../game/game.entity';
+
+@Module({
+  imports: [
+    TypeOrmModule.forFeature([
+      FactionEntity,
+      Game_PersonEntity,
+      GameGroupEntity,
+    ]),
+  ],
+  controllers: [FactionController],
+  providers: [FactionService],
+})
+export class FactionModule {}
diff --git a/src/faction/faction.service.ts b/src/faction/faction.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..67edef1db5d071e1936aba03ded5c5051c1ae713
--- /dev/null
+++ b/src/faction/faction.service.ts
@@ -0,0 +1,149 @@
+import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { Repository, Not } from 'typeorm';
+
+import { FactionEntity, GameGroupEntity } from './faction.entity';
+import { JoinFactionDTO, GameGroupDTO, JoinGameGroupDTO } from './faction.dto';
+import { Game_PersonEntity } from '../game/game.entity';
+
+@Injectable()
+export class FactionService {
+  constructor(
+    @InjectRepository(FactionEntity)
+    private factionRepository: Repository<FactionEntity>,
+    @InjectRepository(Game_PersonEntity)
+    private game_PersonRepository: Repository<Game_PersonEntity>,
+    @InjectRepository(GameGroupEntity)
+    private game_GroupRepository: Repository<GameGroupEntity>,
+  ) {}
+
+  async joinFaction(person, faction: JoinFactionDTO) {
+    // get faction
+    const factionInDb = await this.factionRepository.findOne({
+      factionId: faction.factionId,
+    });
+
+    if (!factionInDb) {
+      throw new HttpException('No factions exist!', HttpStatus.BAD_REQUEST);
+    }
+    //check if password is correct
+    if (factionInDb.passwordCheck(faction.factionPassword)) {
+      const gameperson = await this.game_PersonRepository.create({
+        faction: factionInDb,
+        game: faction.game,
+        role: 'soldier',
+        person: person,
+      });
+      //check if user is already in a faction
+      if (
+        await this.game_PersonRepository.findOne({
+          person: person,
+          game: faction.game,
+        })
+      ) {
+        throw new HttpException(
+          'You have already joined faction!',
+          HttpStatus.BAD_REQUEST,
+        );
+      }
+      // insert to database
+      return await this.game_PersonRepository.save(gameperson);
+    } else {
+      throw new HttpException('Invalid password!', HttpStatus.UNAUTHORIZED);
+    }
+  }
+
+  async promotePlayer(body) {
+    const gamepersonId = body.player;
+    // get playerdata
+    const gameperson = await this.game_PersonRepository.findOne({
+      where: { gamepersonId },
+    });
+    if (gameperson) {
+      const factionleader = await this.game_PersonRepository.create(gameperson);
+      factionleader.role = body.role;
+      return await this.game_PersonRepository.save(factionleader);
+    }
+    throw new HttpException('player does not exist', HttpStatus.BAD_REQUEST);
+  }
+
+  // checks the password, creates an entry in GamePerson table with associated role&faction
+  async createGroup(person, gameId, groupData: GameGroupDTO) {
+    // get gamePerson ref
+    const gamePerson = await this.game_PersonRepository.findOne({
+      person: person,
+      game: gameId,
+    });
+    // check if the authenticated person already belongs to a group
+    if (
+      await this.game_PersonRepository.findOne({
+        group: Not(null),
+        person: person,
+      })
+    ) {
+      throw new HttpException(
+        'You already belong to a group!',
+        HttpStatus.BAD_REQUEST,
+      );
+    }
+
+    // create a group entry and insert it to db
+    const group = await this.game_GroupRepository.create({
+      ...groupData,
+      leader: gamePerson,
+    });
+    const gameGroup = await this.game_GroupRepository.insert(group);
+
+    // update the gamePerson entry with group data
+    gamePerson.group = gamePerson.leaderGroup = gameGroup.identifiers[0]['id'];
+    await this.game_PersonRepository.save(gamePerson);
+
+    return {
+      message: 'created new group',
+    };
+  }
+
+  async showGroups(factionId) {
+    return await this.game_GroupRepository.find({
+      relations: ['leader', 'players'],
+      where: { faction: factionId },
+    });
+  }
+
+  async joinGroup(person, gameId, data: JoinGameGroupDTO) {
+    const gamePerson = await this.game_PersonRepository.findOne({
+      person: person,
+      game: gameId,
+    });
+    gamePerson.group = data.groupId;
+    await this.game_PersonRepository.save(gamePerson);
+    return {
+      message: 'Joined group',
+    };
+  }
+
+  async listFactionMembers(faction) {
+    const members = await this.game_PersonRepository.find({
+      where: { faction },
+      relations: ['person'],
+    });
+    members.sort(function(a, b) {
+      return a['person']['name'].localeCompare(b['person']['name']);
+    });
+    return members;
+  }
+
+  async verifyUser(person, game) {
+    const gameperson = await this.game_PersonRepository.findOne({
+      where: { person, game },
+      relations: ['faction'],
+    });
+    if (gameperson) {
+      return {
+        message: gameperson,
+      };
+    } else {
+      throw new HttpException('No faction was found', HttpStatus.BAD_REQUEST);
+    }
+  }
+}
diff --git a/src/game/coordinate.entity.ts b/src/game/coordinate.entity.ts
deleted file mode 100644
index 851bb65c1b23ad74c06b2eb479710f5d121b08fa..0000000000000000000000000000000000000000
--- a/src/game/coordinate.entity.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import {
-  Entity,
-  Column,
-  PrimaryGeneratedColumn,
-  ManyToOne,
-  Timestamp,
-} from 'typeorm';
-import { GameEntity, Game_PersonEntity } from './game.entity';
-import { FactionEntity } from './faction.entity';
-
-@Entity('MapDrawing')
-export class MapDrawingEntity {
-  @PrimaryGeneratedColumn('uuid') mapDrawingId: string;
-  @Column({ type: 'bool' }) drawingIsActive: boolean;
-  @Column({ type: 'time' }) drawingValidTill: string;
-
-  @Column({ type: 'json', nullable: true }) data: JSON;
-
-  @ManyToOne(type => FactionEntity, faction => faction.factionId)
-  faction: FactionEntity;
-  @ManyToOne(type => GameEntity, gameEntity => gameEntity.id)
-  gameId: GameEntity;
-}
-
-@Entity('Game_Person_MapDrawing')
-export class Game_Person_MapDrawingEntity {
-  @PrimaryGeneratedColumn('uuid') GPmapDrawingId: string;
-  @Column({ type: 'timestamp' }) GPCTimeStamp: Timestamp;
-
-  @ManyToOne(type => Game_PersonEntity, game_person => game_person.gamepersonId)
-  game_person: Game_PersonEntity;
-  @ManyToOne(type => MapDrawingEntity, map_drawing => map_drawing.mapDrawingId)
-  map_drawing: MapDrawingEntity;
-}
diff --git a/src/game/game.controller.spec.ts b/src/game/game.controller.spec.ts
deleted file mode 100644
index 23d9a2f9c849e6b63b31ac707abca1cef9874012..0000000000000000000000000000000000000000
--- a/src/game/game.controller.spec.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Test, TestingModule } from '@nestjs/testing';
-import { GameController } from './game.controller';
-
-describe('Game Controller', () => {
-  let controller: GameController;
-
-  beforeEach(async () => {
-    const module: TestingModule = await Test.createTestingModule({
-      controllers: [GameController],
-    }).compile();
-
-    controller = module.get<GameController>(GameController);
-  });
-
-  it('should be defined', () => {
-    expect(controller).toBeDefined();
-  });
-});
diff --git a/src/game/game.controller.ts b/src/game/game.controller.ts
index edff9d8e21ae4bd667b1eecb7162cacede906678..8d7494ba4dfa4a77e22963600e45a7579fca5d5d 100644
--- a/src/game/game.controller.ts
+++ b/src/game/game.controller.ts
@@ -7,14 +7,18 @@ import {
   Param,
   UsePipes,
   Put,
+  UseInterceptors,
+  ClassSerializerInterceptor,
+  Delete,
 } from '@nestjs/common';
 
 import { GameService } from './game.service';
 import { AuthGuard } from '../shared/auth.guard';
 import { User } from '../user/user.decorator';
-import { GameDTO, GameGroupDTO, FlagboxEventDTO } from './game.dto';
+import { GameDTO, FlagboxEventDTO, GameStateDTO } from './game.dto';
 import { ValidationPipe } from '../shared/validation.pipe';
-import { Roles } from '../shared/roles.decorator';
+import { Roles, GameStates } from '../shared/guard.decorator';
+import { GameEntity } from './game.entity';
 
 @Controller('game')
 export class GameController {
@@ -27,50 +31,27 @@ export class GameController {
     return this.gameservice.createNewGame(person, body);
   }
 
-  @Put(':id')
+  @Put('edit/:id')
   @Roles('admin')
+  @GameStates('CREATED')
   @UsePipes(new ValidationPipe())
   async editGame(@Param('id') id: string, @Body() body: GameDTO) {
+    body.id = id;
     return this.gameservice.editGame(id, body);
   }
 
-  @Post(':id')
-  @UseGuards(new AuthGuard())
-  @UsePipes(new ValidationPipe())
-  async createGroup(
-    @User('id') person,
-    @Param('id') id: string,
-    @Body() data: GameGroupDTO,
-  ) {
-    try {
-      return this.gameservice.createGroup(person, id, data);
-    } catch (error) {}
-  }
-
-  @Get('get-groups')
-  async getGroups() {
-    return this.gameservice.showGroups();
-  }
-
-  @Put('groups/:id')
-  @UseGuards(new AuthGuard())
-  async joinGroup(@User('id') person, @Param('id') id) {
-    return this.gameservice.joinGroup(person, id);
+  @Delete('delete/:id')
+  @Roles('admin')
+  @GameStates('CREATED')
+  async deleteGame(@Param('id') id: string) {
+    return this.gameservice.deleteGame(id);
   }
 
-  @Put('joinfaction')
-  @UseGuards(new AuthGuard())
-  joinFaction(
-    @User('id') person,
-    @Param('id') gameId,
-    @Param('faction') faction: string,
-    @Body() password: string,
-  ) {
-    try {
-      //   return this.gameservice.joinFaction(person, gameId, faction, password);
-    } catch (error) {
-      return error;
-    }
+  @Put('edit-state/:id')
+  @Roles('admin')
+  @UsePipes(new ValidationPipe())
+  async updateGameState(@Param('id') id: string, @Body() body: GameStateDTO) {
+    return this.gameservice.updateGameStatus(body);
   }
 
   @Get('listgames')
@@ -78,17 +59,26 @@ export class GameController {
     return this.gameservice.listGames();
   }
 
+  // ClassSerializerInterceptor removes excluded columns set in Entities
+  @UseInterceptors(ClassSerializerInterceptor)
   @Get(':id')
   async returnGameInfo(@Param('id') id: string) {
     return this.gameservice.returnGameInfo(id);
   }
 
+  @Get('get-factions/:id')
+  @Roles('admin')
+  async returnGameFactions(@Param('id') id: GameEntity) {
+    return this.gameservice.listFactions(id);
+  }
+
   @Get('flag/:id')
   async flagboxQuery(@Param('id') id: string) {
     return this.gameservice.flagboxQuery(id);
   }
 
   @Post('flag/:id')
+  @GameStates('STARTED')
   async flagboxEvent(@Param('id') id: string, @Body() data: FlagboxEventDTO) {
     return this.gameservice.flagboxEvent(id, data);
   }
diff --git a/src/game/game.dto.ts b/src/game/game.dto.ts
index 952956dd30a375bd1c6be4c417757d69288fbc3c..266a8b1564e5b11fb42da755359c79d37f4b170b 100644
--- a/src/game/game.dto.ts
+++ b/src/game/game.dto.ts
@@ -1,20 +1,28 @@
 import {
   IsNotEmpty,
   IsString,
-  IsDate,
   Length,
-  IsInt,
-  Min,
-  Max,
-  IsArray,
-  IsJSON,
   IsDateString,
   IsNumber,
+  Validate,
+  Min,
+  Max,
+  ValidateNested,
+  Allow,
+  IsUUID,
+  IsIn,
+  IsOptional,
 } from 'class-validator';
-import { Timestamp } from 'typeorm';
+
 import { ObjectivePointEntity } from './game.entity';
+import { CenterJSON } from '../shared/custom-validation';
+import { FactionDTO } from '../faction/faction.dto';
+import { CenterDTO, NodeSettingsDTO } from './game.json.dto';
+import { Type } from 'class-transformer';
 
 export class GameDTO {
+  @IsOptional()
+  id: string;
   @IsString()
   @IsNotEmpty()
   @Length(3, 30)
@@ -22,37 +30,60 @@ export class GameDTO {
   @IsNotEmpty()
   @Length(1, 255)
   desc: string;
-  @IsNotEmpty()
-  //@IsJSON()
-  center: JSON;
-  //@IsJSON()
-  // doesn't accept with IsJSON, WIP to get validation for map and center
-  // IsJSON checks with json.parse, expecting string
+  @ValidateNested()
+  @Type(() => CenterDTO)
+  center: CenterDTO;
+  @Allow()
+  @ValidateNested()
+  @Type(() => NodeSettingsDTO)
+  nodesettings?: NodeSettingsDTO;
+  @Allow()
   map?: JSON;
-  nodesettings?: JSON;
   @IsDateString()
   @IsNotEmpty()
   startdate: string;
   @IsDateString()
   @IsNotEmpty()
   enddate: string;
-  // custom validation for array length (arr>min, arr<max)
-  //@Validate(ArrayLength, [4, 8])
+  @ValidateNested()
+  @Type(() => FactionDTO)
   factions?: FactionDTO[];
+  @ValidateNested()
+  @Type(() => FlagboxDTO)
   objective_points?: FlagboxDTO[];
 }
 
-export class FactionDTO {
+export class newGameDTO {
   @IsString()
   @IsNotEmpty()
-  @Length(2, 15)
-  factionName: string;
-  factionPassword: string;
-  multiplier: number;
-  game: GameDTO;
+  @Length(3, 30)
+  name: string;
+  @IsString()
+  @IsNotEmpty()
+  @Length(1, 255)
+  desc: string;
+  @IsNotEmpty()
+  @Validate(CenterJSON)
+  center: JSON;
+  @IsDateString()
+  @IsNotEmpty()
+  startdate: string;
+  @IsDateString()
+  @IsNotEmpty()
+  enddate: string;
+}
+
+export class GameStateDTO {
+  @IsUUID('4')
+  id: string;
+  @IsIn(['CREATED', 'STARTED', 'PAUSED', 'ENDED'])
+  state: string;
 }
 
 export class FlagboxDTO {
+  @IsOptional()
+  @IsUUID('4')
+  objectivePointId: string;
   @IsString()
   @IsNotEmpty()
   @Length(7)
@@ -62,16 +93,22 @@ export class FlagboxDTO {
 }
 
 export class FlagboxEventDTO {
+  @IsString()
+  @IsNotEmpty()
+  @Length(7)
   node_id: string;
-  owner: number;
-  action: number;
-  capture: number;
+  @IsNumber()
+  @Min(0)
+  @Max(3)
+  owner: number; // owner = 0, => no owner, owner = 1, => first entry in faction db
+  @IsNumber()
+  @Min(0)
+  @Max(3)
+  action: number; // 0=no capture ongoing, 1=captured, 2=capture ongoing
+  @IsNumber()
+  @Min(0)
+  @Max(3)
+  capture: number; // which faction is capturing, same logic as in owner with numbers
   oP_HistoryTimestamp?: string;
   objective_point?: ObjectivePointEntity;
 }
-
-export class GameGroupDTO {
-  @IsString()
-  @Length(3, 31)
-  name: string;
-}
diff --git a/src/game/game.entity.ts b/src/game/game.entity.ts
index 36813094bc3a87c0903cb94f81260a42be803116..7ae6e29955d02a2c1368b5f720200f009bd92ee1 100644
--- a/src/game/game.entity.ts
+++ b/src/game/game.entity.ts
@@ -9,13 +9,12 @@ import {
   JoinColumn,
 } from 'typeorm';
 
+import { MapDrawingEntity } from '../draw/coordinate.entity';
 import { PersonEntity } from '../user/user.entity';
-import { GameGroupEntity } from './group.entity';
-import { FactionEntity, TaskEntity } from './faction.entity';
-import {
-  MapDrawingEntity,
-  Game_Person_MapDrawingEntity,
-} from './coordinate.entity';
+import { GameGroupEntity } from '../faction/faction.entity';
+import { FactionEntity } from '../faction/faction.entity';
+import { TaskEntity } from '../task/task.entity';
+import { CenterDTO, NodeSettingsDTO } from './game.json.dto';
 
 // table that stores all created games
 @Entity('Game')
@@ -23,23 +22,24 @@ export class GameEntity {
   @PrimaryGeneratedColumn('uuid') id: string;
   @Column('text') name: string;
   @Column('text') desc: string;
-  @Column('json') center: JSON;
+  @Column('json') center: CenterDTO;
   @Column({ type: 'json', nullable: true }) map: JSON;
-  @Column({ type: 'json', nullable: true }) nodesettings?: JSON;
+  @Column({ type: 'json', nullable: true }) nodesettings?: NodeSettingsDTO;
+  @Column('text') state: string;
   @Column('timestamp') startdate: Timestamp;
   @Column('timestamp') enddate: Timestamp;
 
-  @OneToMany(type => FactionEntity, factions => factions.factionId)
+  @OneToMany(type => FactionEntity, factions => factions.game)
   factions: FactionEntity[];
   @OneToMany(type => Game_PersonEntity, game_persons => game_persons.game)
   game_persons: Game_PersonEntity[];
-  @OneToMany(type => GameGroupEntity, group => group.game)
-  groups: GameGroupEntity[];
   @OneToMany(
     type => ObjectivePointEntity,
     objective_points => objective_points.game,
   )
   objective_points: ObjectivePointEntity[];
+  @OneToMany(type => TaskEntity, tasks => tasks.taskGame)
+  tasks: TaskEntity[];
 
   gameObject() {
     const { id, name } = this;
@@ -48,23 +48,28 @@ export class GameEntity {
 }
 
 // table that stores players associated with particular game
-@Entity('Game_Person')
+@Entity('Game_Person', {
+  orderBy: {
+    person: 'ASC',
+  },
+})
 export class Game_PersonEntity {
   @PrimaryGeneratedColumn('uuid') gamepersonId: string;
   @Column({ type: 'text', nullable: true }) role: string;
-  @ManyToOne(type => FactionEntity, faction => faction)
+  @ManyToOne(type => FactionEntity, faction => faction.game_persons, {
+    onDelete: 'CASCADE',
+  })
   faction: FactionEntity;
-  @ManyToOne(type => GameEntity, game => game.id)
+  @ManyToOne(type => GameEntity, game => game.id, {
+    onDelete: 'CASCADE',
+  })
   game: GameEntity;
   @ManyToOne(type => PersonEntity, person => person.id)
   person: PersonEntity;
-  @OneToOne(type => GameGroupEntity, group => group.leader, {
-    onDelete: 'CASCADE',
-  })
-  @JoinColumn({ name: 'leaderGroup' })
+  @OneToOne(type => GameGroupEntity, group => group.leader)
   leaderGroup: GameGroupEntity;
   @ManyToOne(type => GameGroupEntity, group => group.players, {
-    onDelete: 'CASCADE',
+    onDelete: 'NO ACTION',
   })
   @JoinColumn({ name: 'group' })
   group: GameGroupEntity;
@@ -76,9 +81,13 @@ export class ObjectivePointEntity {
   @Column({ type: 'text' }) objectivePointDescription: string;
   @Column({ type: 'float' }) objectivePointMultiplier: number;
 
-  @ManyToOne(type => MapDrawingEntity, coordinate => coordinate.data)
+  @ManyToOne(type => MapDrawingEntity, coordinate => coordinate.data, {
+    onDelete: 'CASCADE',
+  })
   coordinate: MapDrawingEntity;
-  @ManyToOne(type => GameEntity, game => game.objective_points)
+  @ManyToOne(type => GameEntity, game => game.objective_points, {
+    onDelete: 'CASCADE',
+  })
   game: GameEntity;
 }
 
@@ -87,13 +96,20 @@ export class ObjectivePoint_HistoryEntity {
   @PrimaryGeneratedColumn('uuid') oP_HistoryId: string;
   @Column({ type: 'timestamp' }) oP_HistoryTimestamp: Timestamp;
   @Column('float') action: number;
-  @ManyToOne(type => FactionEntity, factionEntity => factionEntity.factionId)
+  @ManyToOne(type => FactionEntity, factionEntity => factionEntity.factionId, {
+    onDelete: 'CASCADE',
+  })
   capture: FactionEntity;
-  @ManyToOne(type => FactionEntity, factionentity => factionentity.factionId)
+  @ManyToOne(type => FactionEntity, factionentity => factionentity.factionId, {
+    onDelete: 'CASCADE',
+  })
   owner: FactionEntity;
   @ManyToOne(
     type => ObjectivePointEntity,
     objective_point => objective_point.objectivePointId,
+    {
+      onDelete: 'CASCADE',
+    },
   )
-  objective_point: ObjectivePointEntity;
+  objective_point: string;
 }
diff --git a/src/game/game.json-nested.dto.ts b/src/game/game.json-nested.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..df67071f089caf3670e46188f92959cfa4e349ad
--- /dev/null
+++ b/src/game/game.json-nested.dto.ts
@@ -0,0 +1,16 @@
+import { IsNumber } from 'class-validator';
+
+export class NodeCoreSettingsDTO {
+  @IsNumber()
+  capture_time: number;
+  @IsNumber()
+  confirmation_time: number;
+  @IsNumber()
+  owner: number;
+  @IsNumber()
+  capture: number;
+  @IsNumber()
+  buttons_available: number;
+  @IsNumber()
+  heartbeat_interval: number;
+}
diff --git a/src/game/game.json.dto.ts b/src/game/game.json.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5b9484aaa3334d6d564398a96c7e2747f86aab84
--- /dev/null
+++ b/src/game/game.json.dto.ts
@@ -0,0 +1,16 @@
+import { IsNumber, ValidateNested } from 'class-validator';
+import { NodeCoreSettingsDTO } from './game.json-nested.dto';
+import { Type } from 'class-transformer';
+
+export class CenterDTO {
+  @IsNumber()
+  lat: number;
+  @IsNumber()
+  lng: number;
+}
+
+export class NodeSettingsDTO {
+  @ValidateNested()
+  @Type(() => NodeCoreSettingsDTO)
+  node_settings: NodeCoreSettingsDTO;
+}
diff --git a/src/game/game.module.ts b/src/game/game.module.ts
index c908e483b7b1a867d5d8dfb8e8fab54ea212ecfe..1c9e86faf59645bf537e76a8720bb6ab741fe6bd 100644
--- a/src/game/game.module.ts
+++ b/src/game/game.module.ts
@@ -10,8 +10,8 @@ import {
   ObjectivePoint_HistoryEntity,
 } from './game.entity';
 import { PersonEntity } from '../user/user.entity';
-import { GameGroupEntity } from './group.entity';
-import { FactionEntity } from './faction.entity';
+import { GameGroupEntity } from '../faction/faction.entity';
+import { FactionEntity } from '../faction/faction.entity';
 import { NotificationModule } from '../notifications/notifications.module';
 
 @Module({
diff --git a/src/game/game.service.spec.ts b/src/game/game.service.spec.ts
deleted file mode 100644
index f4a1db7e70bf2a0e38c6d430c95e54feb3934fdf..0000000000000000000000000000000000000000
--- a/src/game/game.service.spec.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Test, TestingModule } from '@nestjs/testing';
-import { GameService } from './game.service';
-
-describe('GameService', () => {
-  let service: GameService;
-
-  beforeEach(async () => {
-    const module: TestingModule = await Test.createTestingModule({
-      providers: [GameService],
-    }).compile();
-
-    service = module.get<GameService>(GameService);
-  });
-
-  it('should be defined', () => {
-    expect(service).toBeDefined();
-  });
-});
diff --git a/src/game/game.service.ts b/src/game/game.service.ts
index ea11a669de95f43f89f8b3a7f798358e63421bbe..3f6506b649f7dbe09936e283b4658f9765be8ec4 100644
--- a/src/game/game.service.ts
+++ b/src/game/game.service.ts
@@ -8,11 +8,10 @@ import {
   ObjectivePointEntity,
   ObjectivePoint_HistoryEntity,
 } from './game.entity';
-import { GameDTO, FlagboxEventDTO } from './game.dto';
+import { GameDTO, FlagboxEventDTO, GameStateDTO } from './game.dto';
 import { PersonEntity } from '../user/user.entity';
-import { GameGroupEntity } from './group.entity';
-import { FactionEntity } from './faction.entity';
-import { NotificationGateway } from 'src/notifications/notifications.gateway';
+import { FactionEntity } from '../faction/faction.entity';
+import { NotificationGateway } from '../notifications/notifications.gateway';
 
 @Injectable()
 export class GameService {
@@ -21,12 +20,8 @@ export class GameService {
     private gameRepository: Repository<GameEntity>,
     @InjectRepository(FactionEntity)
     private factionRepository: Repository<FactionEntity>,
-    @InjectRepository(PersonEntity)
-    private personRepository: Repository<PersonEntity>,
     @InjectRepository(Game_PersonEntity)
     private game_PersonRepository: Repository<Game_PersonEntity>,
-    @InjectRepository(GameGroupEntity)
-    private game_GroupRepository: Repository<GameGroupEntity>,
     @InjectRepository(ObjectivePointEntity)
     private objectivePointRepository: Repository<ObjectivePointEntity>,
     @InjectRepository(ObjectivePoint_HistoryEntity)
@@ -38,191 +33,148 @@ export class GameService {
 
   // create a new game
   async createNewGame(personId: PersonEntity, gameData: GameDTO) {
-    try {
-      // checks if a game with the same name exists already
-      const { name } = gameData;
-      if (await this.gameRepository.findOne({ where: { name } })) {
-        throw new HttpException('Game already exists', HttpStatus.BAD_REQUEST);
-      }
-      // else add the game to the database
-      const game = await this.gameRepository.create({
-        ...gameData,
-        factions: gameData.factions,
-      });
-      await this.gameRepository.insert(game);
-      const gamePerson = await this.game_PersonRepository.create({
-        faction: null,
-        game: game,
-        person: personId,
-      });
-      gamePerson['role'] = 'admin';
-      await this.game_PersonRepository.insert(gamePerson);
-      return {
-        message: 'New game added',
-      };
-    } catch (error) {
-      return error.message;
+    // checks if a game with the same name exists already
+    if (await this.gameRepository.findOne({ name: gameData.name })) {
+      throw new HttpException('Game already exists', HttpStatus.BAD_REQUEST);
     }
+    // else add the game to the database
+    const game = await this.gameRepository.create(gameData);
+    game.state = 'CREATED';
+    await this.gameRepository.insert(game);
+    // add gamePerson with role admin to the game
+    const gamePerson = await this.game_PersonRepository.create({
+      game: game,
+      person: personId,
+      role: 'admin',
+    });
+    await this.game_PersonRepository.insert(gamePerson);
+    return {
+      message: 'New game added',
+    };
   }
 
   // edit already created game
-  async editGame(id: string, gameData: GameDTO) {
-    try {
-      // checks if a game with the same name exists already
-      const { name } = gameData;
-      if (await this.gameRepository.findOne({ name: name, id: Not(id) })) {
-        throw new HttpException('Game already exists', HttpStatus.BAD_REQUEST);
-      }
-      // update game entry in db
-      const updatedGame = await this.gameRepository.create({
-        ...gameData,
-        factions: null,
-        objective_points: null,
-      });
-      updatedGame['id'] = id;
-      const gameId = await this.gameRepository.save(updatedGame);
+  async editGame(id, gameData: GameDTO) {
+    // checks if a game with the same name exists already
+    if (
+      await this.gameRepository.findOne({ name: gameData.name, id: Not(id) })
+    ) {
+      throw new HttpException(
+        'Game with the same name already exists',
+        HttpStatus.BAD_REQUEST,
+      );
+    }
 
-      // get all the factions that are associated with the game to deny duplicate entries
-      const factions = await this.factionRepository.find(gameId);
-      const factionNames = factions.map(({ factionName }) => factionName);
-      // add the factions to db
-      if (gameData.factions) {
-        gameData.factions.map(async faction => {
-          if (!Object.values(factionNames).includes(faction.factionName)) {
-            let name = await this.factionRepository.create({
-              ...faction,
-              gameId: gameId,
-            });
-            await this.factionRepository.insert(name);
-          }
-        });
-      }
+    // check for duplicate names in gameData
+    const factionNames = gameData.factions.map(
+      ({ factionName }) => factionName,
+    );
+    const flagboxNodeIds = gameData.objective_points.map(
+      ({ objectivePointDescription }) => objectivePointDescription,
+    );
+    if (
+      new Set(factionNames).size !== factionNames.length ||
+      new Set(flagboxNodeIds).size !== flagboxNodeIds.length
+    ) {
+      throw new HttpException(
+        'No duplicate names allowed!',
+        HttpStatus.BAD_REQUEST,
+      );
+    }
 
-      // get old flagboxes to deny duplicate entries
-      const flagboxes = await this.objectivePointRepository.find({
-        game: gameId,
+    // get factions that have been added previously
+    let factions = await this.factionRepository.find({ game: id });
+    // get flagboxes that have been added previously
+    let flagboxes = await this.objectivePointRepository.find({
+      game: id,
+    });
+    // update game entry in db
+    const updatedGame = await this.gameRepository.create(gameData);
+    const gameId = await this.gameRepository.save(updatedGame);
+    // iterate factions if any were added
+    if (gameData.factions) {
+      const factionIds = gameData.factions.map(({ factionId }) => factionId);
+      // delete all existing factions that are not in submitted data
+      factions.map(async faction => {
+        if (!factionIds.includes(faction.factionId)) {
+          await this.factionRepository.delete(faction);
+        }
       });
-      const flagboxIds = flagboxes.map(
-        ({ objectivePointDescription }) => objectivePointDescription,
-      );
-      // insert the flagboxes to db
-      if (gameData.objective_points) {
-        gameData.objective_points.map(async flagbox => {
-          if (
-            !Object.values(flagboxIds).includes(
-              flagbox.objectivePointDescription,
-            )
-          ) {
-            let newFlagbox = await this.objectivePointRepository.create({
-              ...flagbox,
-              game: gameId,
-            });
-            await this.objectivePointRepository.insert(newFlagbox);
-          }
+      // create / update factions present in the submitted data
+      gameData.factions.map(async faction => {
+        let name = await this.factionRepository.create({
+          ...faction,
+          game: gameId,
         });
-      }
-
-      // TO DO: ADD FLAGBOX LOCATION TO MAPDRAWING ENTITY
+        await this.factionRepository.save(name);
+      });
+    } else {
+      // if no factions are present in data, delete all factions associated with the game
+      await this.factionRepository.delete({ game: id });
+    }
 
-      return {
-        message: 'Game updated',
-      };
-    } catch (error) {
-      return error;
+    // insert the flagboxes to db
+    if (gameData.objective_points) {
+      const flagboxIds = gameData.objective_points.map(
+        ({ objectivePointId }) => objectivePointId,
+      );
+      flagboxes.map(async flagbox => {
+        if (!flagboxIds.includes(flagbox.objectivePointDescription)) {
+          await this.objectivePointRepository.delete(flagbox);
+        }
+      });
+      gameData.objective_points.map(async flagbox => {
+        let newFlagbox = await this.objectivePointRepository.create({
+          ...flagbox,
+          game: gameId,
+        });
+        await this.objectivePointRepository.save(newFlagbox);
+      });
+    } else {
+      await this.objectivePointRepository.delete({ game: id });
     }
-  }
 
-  async deleteGame(id) {
-    // TODO: Delete factions from Faction table associated with the deleted game
-    await this.gameRepository.delete({ id });
+    // TO DO: ADD FLAGBOX LOCATION TO MAPDRAWING ENTITY
+
     return {
-      message: 'Game deleted',
+      message: 'Game updated',
     };
   }
 
-  // checks the password, creates an entry in GamePerson table with associated role&faction
-  async createGroup(person, gameId, groupData) {
-    try {
-      // check if the person already is in a group in this game
-      const checkDuplicate = await this.game_PersonRepository.findOne({
-        person: person,
-      });
-      if (checkDuplicate) {
-        throw new HttpException(
-          'You already belong to a group!',
-          HttpStatus.BAD_REQUEST,
-        );
-      }
-
-      // create a group entry and insert it to db
-      const group = await this.game_GroupRepository.create({
-        ...groupData,
-        game: gameId,
-      });
-      const gameGroup = await this.game_GroupRepository.insert(group);
-
-      // create game_Person entry and insert it to db
-      const gamePerson = await this.game_PersonRepository.create({
-        role: 'soldier',
-        faction: null,
-        game: gameId,
-        person: person,
-        leaderGroup: gameGroup.identifiers[0]['id'],
-        group: gameGroup.identifiers[0]['id'],
+  async updateGameStatus(game: GameStateDTO) {
+    const updatedGame = await this.gameRepository.findOne({ id: game.id });
+    if (updatedGame) {
+      updatedGame.state = game.state;
+      await this.gameRepository.save(updatedGame);
+      // notify players about game state change
+      this.notificationGateway.server.emit(game.id, {
+        type: 'gamestate-update',
       });
-      await this.game_PersonRepository.insert(gamePerson);
-
       return {
-        message: 'created new group',
+        message: 'State was updated',
       };
-    } catch (e) {
-      return e;
     }
+    throw new HttpException("Game doesn't exist", HttpStatus.BAD_REQUEST);
   }
 
-  async showGroups() {
-    try {
-      return await this.game_GroupRepository.find({
-        relations: ['leader', 'players', 'game'],
-      });
-    } catch (e) {
-      return e;
-    }
+  async listFactions(game: GameEntity) {
+    return this.factionRepository.find({ game });
   }
 
-  async joinGroup(person, groupId) {
-    try {
-      const gameData = await this.game_GroupRepository.findOne({
-        where: { id: groupId },
-        relations: ['players', 'game'],
-      });
-      const gamePerson = await this.game_PersonRepository.create({
-        role: 'soldier',
-        faction: null,
-        game: gameData.game,
-        person: person,
-        leaderGroup: null,
-        group: groupId,
-      });
-      await this.game_PersonRepository.insert(gamePerson);
-      return {
-        message: 'Joined group',
-      };
-    } catch (e) {
-      return e;
-    }
+  async deleteGame(id) {
+    // TODO: Delete factions from Faction table associated with the deleted game
+    await this.gameRepository.delete({ id });
+    return {
+      message: 'Game deleted',
+    };
   }
 
   // returns name and id of each game
   async listGames() {
-    try {
-      const games = await this.gameRepository.find();
-      return games.map(game => {
-        return game.gameObject();
-      });
-    } catch (error) {
-      return error;
-    }
+    const games = await this.gameRepository.find();
+    return games.map(game => {
+      return game.gameObject();
+    });
   }
 
   // returns information about a game identified by id
@@ -231,6 +183,10 @@ export class GameService {
       where: { id: id },
       relations: ['factions', 'objective_points'],
     });
+    // sort factions by their name
+    game.factions.sort(function(a, b) {
+      return a['factionName'].localeCompare(b['factionName']);
+    });
     return game;
   }
 
@@ -243,7 +199,7 @@ export class GameService {
   // add events to history and send updates with socket
   async flagboxEvent(gameId, data: FlagboxEventDTO) {
     // get all the factions associated with the game
-    const factionRef = await this.factionRepository.find({ gameId: gameId });
+    const factionRef = await this.factionRepository.find({ game: gameId });
     // get reference to the objective
     const objectiveRef = await this.objectivePointRepository.findOne({
       where: { objectivePointDescription: data.node_id, game: gameId },
@@ -252,12 +208,16 @@ export class GameService {
     const eventUpdate = await this.objectivePoint_HistoryRepository.create({
       oP_HistoryTimestamp: data.oP_HistoryTimestamp,
       action: data.action,
-      capture: factionRef[data.capture],
-      owner: factionRef[data.owner],
-      objective_point: objectiveRef,
+      // -1 as 0 means null
+      capture: data.capture !== 0 ? factionRef[data.capture - 1] : null,
+      owner: data.owner !== 0 ? factionRef[data.owner - 1] : null,
+      objective_point: objectiveRef.objectivePointId,
     });
     await this.objectivePoint_HistoryRepository.insert(eventUpdate);
     // send flagbox event to flagbox subscribers
-    this.notificationGateway.server.emit('flagbox', 'event update');
+    this.notificationGateway.server.emit(gameId, { type: 'flagbox-event' });
+    return {
+      message: 'OK',
+    };
   }
 }
diff --git a/src/game/group.entity.ts b/src/game/group.entity.ts
deleted file mode 100644
index 0b9f00ed621b41b8515a77126f9564c14a02d74b..0000000000000000000000000000000000000000
--- a/src/game/group.entity.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import {
-    Entity,
-    Column,
-    PrimaryGeneratedColumn,
-    ManyToOne,
-    OneToMany,
-    OneToOne,
-    JoinColumn,
-  } from 'typeorm';
-  
-import { Game_PersonEntity, GameEntity } from './game.entity';
-
-@Entity('GameGroup')
-export class GameGroupEntity {
-  @PrimaryGeneratedColumn('uuid') id: string;
-  @Column('text') name: string;
-  @OneToOne(type => Game_PersonEntity, person => person.leaderGroup, {
-      onDelete: 'CASCADE'
-  })
-  //@JoinColumn({name:'leader'})
-  leader: Game_PersonEntity;
-  @OneToMany(type => Game_PersonEntity, person => person.group, {
-      onDelete: 'CASCADE'
-  })
-  players: Game_PersonEntity[];
-  @ManyToOne(type => GameEntity, game => game.groups)
-  game: GameEntity;
-}
\ No newline at end of file
diff --git a/src/main.ts b/src/main.ts
index 1e3e4e147bc386a4ce15a36bf274face5fd14c1e..68871be82d89a37a410b93b252fb6f1e712ad143 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,7 +3,6 @@ import * as rateLimit from 'express-rate-limit';
 
 import { AppModule } from './app.module';
 
-
 /*
   Main.ts starts the server.
 */
@@ -13,7 +12,7 @@ import { AppModule } from './app.module';
 // see https://github.com/nfriedly/express-rate-limit/issues/138
 const limiter = (rateLimit as any)({
   windowMs: 60 * 1000, // one minute
-  max: 100 // limit each IP to 100 requests per windowMs
+  max: 100, // limit each IP to 100 requests per windowMs
 });
 
 async function bootstrap() {
diff --git a/src/mapmarkers/mapmarker.dto.ts b/src/mapmarkers/mapmarker.dto.ts
deleted file mode 100644
index f9821f4cbc73b62582263ac63e29c07a75a46b44..0000000000000000000000000000000000000000
--- a/src/mapmarkers/mapmarker.dto.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { IsString, IsJSON } from 'class-validator';
-/*
-DTO: MapMarker
-- represents servers data handling.
-*/
-
-
-export class MapMarkerDTO {
-    @IsString()
-    type:string;
-    @IsString()
-    latitude: string;
-    @IsString()
-    longitude: string;
-    @IsString()
-    timestamp: string;    
-    @IsJSON()
-    features: JSON;
-}
\ No newline at end of file
diff --git a/src/mapmarkers/mapmarker.entity.ts b/src/mapmarkers/mapmarker.entity.ts
deleted file mode 100644
index 0b26cbaa9a869fd81c7669a557b233a32c67b0f4..0000000000000000000000000000000000000000
--- a/src/mapmarkers/mapmarker.entity.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import {
-  Entity,
-  Column,
-  PrimaryGeneratedColumn,
-  Timestamp,
-  ManyToOne,
-} from 'typeorm';
-
-import { PersonEntity } from '../user/user.entity';
-import { GameEntity, Game_PersonEntity } from 'src/game/game.entity';
-
-/*
-  Entity: MapMarker 
-  - represents data that database contains on mapmarker
-  */
-
-/* @Entity('MapMarker')
-  export class MapMarkerEntity {
-    @PrimaryGeneratedColumn('uuid') id: string;
-    @Column({ type: 'text', nullable: true }) latitude: string;
-    @Column({ type: 'text', nullable: true }) longitude: string;
-    @Column({ type: 'timestamp' }) timestamp: Timestamp;
-    @Column({ type: 'json', nullable: true }) features: JSON;
-    @ManyToOne(type => Game_PersonEntity, player => player.markers)
-    player: Game_PersonEntity;
-  }
-  */
diff --git a/src/mapmarkers/mapmarker.service.ts b/src/mapmarkers/mapmarker.service.ts
deleted file mode 100644
index f320d17b0892cec302281a1ee6f99b13fb788b78..0000000000000000000000000000000000000000
--- a/src/mapmarkers/mapmarker.service.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { Injectable } from '@nestjs/common';
-import { Repository } from 'typeorm';
-import { InjectRepository } from '@nestjs/typeorm';
-
-import { MapMarkerEntity } from './mapmarker.entity';
-import { MapMarkerDTO } from './mapmarker.dto';
-import { PersonEntity } from '../user/user.entity';
-
-@Injectable()
-export class MapMarkerService {
-  constructor(
-    //create references to tables as repositories
-    @InjectRepository(MapMarkerEntity)
-    private mapmarkerRepository: Repository<MapMarkerEntity>,
-    @InjectRepository(PersonEntity)
-    private personRepository: Repository<PersonEntity>,
-  ) {}
-
-  // insert marker
-  async insertLocation(personId: string, data: MapMarkerDTO) {
-    try {
-      //get functions runtime as timestamp
-      data.timestamp = new Date(Date.now()).toLocaleString();
-      //check from database for the user who uploads the data
-      const user = await this.personRepository.findOne({
-        where: { id: personId },
-      });
-      //create&copy entity properties
-      const location = await this.mapmarkerRepository.create({
-        ...data,
-      });
-      // insert created entity NOTE: insert method doesn't check for duplicates.
-      await this.mapmarkerRepository.insert(location);
-      // return data and player id&name
-      return { ...data };
-    } catch (error) {
-      return error;
-    }
-  }
-
-  // get all markers
-  async getAllMarkers() {
-    try {
-      // find all markers with specified player
-      const markers = await this.mapmarkerRepository.find({
-        relations: ['player'],
-      });
-      // return markers from database with said playerdata
-      return markers.map(marker => {
-        return { ...marker };
-      });
-    } catch (error) {
-      return error.message;
-    }
-  }
-}
diff --git a/src/mapmarkers/mapmarkers.controller.spec.ts b/src/mapmarkers/mapmarkers.controller.spec.ts
deleted file mode 100644
index 95cbd74e5c45f9713337458335c52257bf5d1220..0000000000000000000000000000000000000000
--- a/src/mapmarkers/mapmarkers.controller.spec.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Test, TestingModule } from '@nestjs/testing';
-import { MapMarkersController } from './mapmarkers.controller';
-
-describe('Mapmarkers Controller', () => {
-  let controller: MapMarkersController;
-
-  beforeEach(async () => {
-    const module: TestingModule = await Test.createTestingModule({
-      controllers: [MapMarkersController],
-    }).compile();
-
-    controller = module.get<MapMarkersController>(MapMarkersController);
-  });
-
-  it('should be defined', () => {
-    expect(controller).toBeDefined();
-  });
-});
diff --git a/src/mapmarkers/mapmarkers.controller.ts b/src/mapmarkers/mapmarkers.controller.ts
deleted file mode 100644
index fef971652de596196169251c202378c67902babd..0000000000000000000000000000000000000000
--- a/src/mapmarkers/mapmarkers.controller.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Controller, Body, Get, Put, UseGuards } from '@nestjs/common';
-
-import { MapMarkerService } from './mapmarker.service';
-import { MapMarkerDTO } from './mapmarker.dto';
-import { AuthGuard } from '../shared/auth.guard';
-import { User } from '../user/user.decorator';
-
-@Controller('mapmarkers')
-export class MapMarkersController {
-    constructor(private mapmarkerservice: MapMarkerService){}
-
-    // Insert figure location, needs "authorization" header with valid Bearer token and content-type json
-    @Put('insert-location')
-    @UseGuards(new AuthGuard())
-    async insertLocation(@User('id') person, @Body() data: MapMarkerDTO): Promise<string>{
-        try {
-            return this.mapmarkerservice.insertLocation(person, data);
-        } catch (error) {
-            return error;
-        }
-    }
-
-    // return all markers through service
-    @Get('getall')
-    async getAll(){
-        try{
-            return this.mapmarkerservice.getAllMarkers();
-        }catch(error){
-            return error.message;
-        }
-    }
-}
diff --git a/src/mapmarkers/mapmarkers.module.ts b/src/mapmarkers/mapmarkers.module.ts
deleted file mode 100644
index a69970ec970f6f70adc8b38351364698c9e61a1e..0000000000000000000000000000000000000000
--- a/src/mapmarkers/mapmarkers.module.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { Module } from '@nestjs/common';
-import { TypeOrmModule } from '@nestjs/typeorm';
-
-import { MapMarkersController } from './mapmarkers.controller';
-import { MapMarkerService } from './mapmarker.service';
-/*import { MapMarkerEntity } from './mapmarker.entity';
-import { PersonEntity } from '../user/user.entity';
-
-@Module({
-  imports: [TypeOrmModule.forFeature([MapMarkerEntity, PersonEntity])],
-  controllers: [MapMarkersController],
-  providers: [MapMarkerService]
-})
-export class MapMarkerModule {}*/
diff --git a/src/notifications/notification.dto.ts b/src/notifications/notification.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..807af14058161062d61c9b88a1d8e56637004acc
--- /dev/null
+++ b/src/notifications/notification.dto.ts
@@ -0,0 +1,12 @@
+import { IsString, Length, IsUUID, IsIn } from 'class-validator';
+
+export class NotificationdDTO {
+  // alert is for serious messages, note is for smaller updates on a situation
+  @IsIn(['alert', 'note'])
+  type: string;
+  @IsString()
+  @Length(0, 63)
+  message: string;
+  @IsUUID('4')
+  game: string;
+}
diff --git a/src/notifications/notification.entity.ts b/src/notifications/notification.entity.ts
index 3f8781633ec42bc3132c5df92f4f74045721506b..f9d5dca9290c30da406a63adf56ee06fe716a7b5 100644
--- a/src/notifications/notification.entity.ts
+++ b/src/notifications/notification.entity.ts
@@ -1,11 +1,23 @@
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from "typeorm";
+import {
+  Entity,
+  PrimaryGeneratedColumn,
+  Column,
+  CreateDateColumn,
+  ManyToOne,
+} from 'typeorm';
+
+import { GameEntity } from '../game/game.entity';
 
 // temporary table for warning notifications
 @Entity('Notifications')
 export class NotificationEntity {
-    @PrimaryGeneratedColumn('uuid') id: string;
-    @Column({type: 'text'}) message: string;
-    @CreateDateColumn() issued: Date;
-    // TODO:
-    // when game creation has been implemented, add logic so that the notifications are tied to games
-}
\ No newline at end of file
+  @PrimaryGeneratedColumn('uuid') id: string;
+  @Column('text') type: string;
+  @Column({ type: 'text' }) message: string;
+  @CreateDateColumn() issued: Date;
+
+  @ManyToOne(type => GameEntity, game => game.id, {
+    onDelete: 'CASCADE',
+  })
+  game: string;
+}
diff --git a/src/notifications/notifications.gateway.ts b/src/notifications/notifications.gateway.ts
index c30114895ffa8d4b40c3cedeaf827c5b3401cb25..5e952d6c78c6f35977f362a7459c0ebf65d1ab5e 100644
--- a/src/notifications/notifications.gateway.ts
+++ b/src/notifications/notifications.gateway.ts
@@ -6,12 +6,15 @@ import {
   OnGatewayConnection,
   OnGatewayDisconnect,
 } from '@nestjs/websockets';
-import { Logger } from '@nestjs/common';
+import { Logger, UsePipes } from '@nestjs/common';
 import { InjectRepository } from '@nestjs/typeorm';
 import { Server, Socket } from 'socket.io';
 import { Repository } from 'typeorm';
 
 import { NotificationEntity } from './notification.entity';
+import { GameEntity } from '../game/game.entity';
+import { NotificationdDTO } from './notification.dto';
+import { ValidationPipe } from '../shared/validation.pipe';
 
 @WebSocketGateway()
 export class NotificationGateway
@@ -20,6 +23,8 @@ export class NotificationGateway
     //create references to tables as repositories
     @InjectRepository(NotificationEntity)
     private notificationRepository: Repository<NotificationEntity>,
+    @InjectRepository(GameEntity)
+    private gameRepository: Repository<GameEntity>,
   ) {}
   @WebSocketServer()
   server: Server;
@@ -40,14 +45,17 @@ export class NotificationGateway
   }
 
   // notifications for when game needs to be paused / stopped
-  @SubscribeMessage('shutItDown')
-  async handleMessage(client: Socket, text: string) {
-    this.logger.log(text);
-    // send the message to all clients listening to warningToPlayers branch
-    this.server.emit('warningToPlayers', text);
-    // create entity properties
-    const message = await this.notificationRepository.create({ message: text });
-    // insert created entity NOTE: insert method doesn't check for duplicates.
-    await this.notificationRepository.insert(message);
+  @SubscribeMessage('game-info')
+  @UsePipes(new ValidationPipe())
+  async handleMessage(client: Socket, data: NotificationdDTO) {
+    // check if the game exists and is either started or paused
+    const game = await this.gameRepository.findOne({ id: data.game });
+    if (game && ['STARTED', 'PAUSED'].includes(game.state)) {
+      // send the message to all clients listening to gameId branch
+      this.server.emit(data.game, data);
+      // create entry for notification in db
+      const message = await this.notificationRepository.create(data);
+      await this.notificationRepository.insert(message);
+    }
   }
 }
diff --git a/src/notifications/notifications.module.ts b/src/notifications/notifications.module.ts
index 97cf59c1f929cfc14b5335b0308e7615ac10dee8..41e2fcaa36d1928dff9a60bd2c6853e240baf16f 100644
--- a/src/notifications/notifications.module.ts
+++ b/src/notifications/notifications.module.ts
@@ -1,10 +1,12 @@
 import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
+
 import { NotificationGateway } from './notifications.gateway';
 import { NotificationEntity } from './notification.entity';
-import { TypeOrmModule } from '@nestjs/typeorm';
+import { GameEntity } from '../game/game.entity';
 
 @Module({
-  imports: [TypeOrmModule.forFeature([NotificationEntity])],
+  imports: [TypeOrmModule.forFeature([NotificationEntity, GameEntity])],
   providers: [NotificationGateway],
   exports: [NotificationGateway],
 })
diff --git a/src/score/score.controller.ts b/src/score/score.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..73fda22e699f5702b1616360bd7e95f0ac8aeb10
--- /dev/null
+++ b/src/score/score.controller.ts
@@ -0,0 +1,36 @@
+import { Controller, Post, UsePipes, Body, Param, Get } from '@nestjs/common';
+
+import { ValidationPipe } from '../shared/validation.pipe';
+import { ScoreService } from './score.service';
+import { ScoreDTO } from './score.dto';
+import { GameEntity } from '../game/game.entity';
+import { Roles, GameStates } from '../shared/guard.decorator';
+
+@Controller('score')
+export class ScoreController {
+  constructor(private scoreService: ScoreService) {}
+
+  // adds score manually to Faction
+  // :id is gameId
+  @Post('add-score/:id')
+  @Roles('admin')
+  @GameStates('STARTED')
+  @UsePipes(new ValidationPipe())
+  async addingScore(@Body() data: ScoreDTO, @Param('id') gameId: GameEntity) {
+    return this.scoreService.addScore(data, gameId);
+  }
+
+  // temporary scoreTick path, :id is gameId
+  @Get('tick-score/:id')
+  @GameStates('STARTED')
+  async scoreTick(@Param('id') gameId: GameEntity) {
+    return this.scoreService.scoreTick(gameId);
+  }
+
+  // shows scores, :id is gameId 
+  @Get('get-score/:id')
+  @GameStates('STARTED')
+  async getScores(@Param('id') gameId: GameEntity) {
+    return this.scoreService.getScores(gameId);
+  }
+}
diff --git a/src/score/score.dto.ts b/src/score/score.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..99955f56eff34a41ce46111d7fd0cb9cd597386f
--- /dev/null
+++ b/src/score/score.dto.ts
@@ -0,0 +1,10 @@
+import { IsNumber, Min, Max, IsUUID } from 'class-validator';
+
+export class ScoreDTO {
+  @IsNumber()
+  @Min(1)
+  @Max(99)
+  score: number;
+  @IsUUID('4')
+  faction: string;
+}
diff --git a/src/score/score.entity.ts b/src/score/score.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6ca9ab77b968060a6dc88c860425119914cec030
--- /dev/null
+++ b/src/score/score.entity.ts
@@ -0,0 +1,21 @@
+import {
+  Entity,
+  PrimaryGeneratedColumn,
+  Column,
+  ManyToOne,
+  Timestamp,
+  CreateDateColumn,
+} from 'typeorm';
+import { FactionEntity } from '../faction/faction.entity';
+
+@Entity('Score')
+export class ScoreEntity {
+  @PrimaryGeneratedColumn('uuid') scoreId: string;
+  @Column({ type: 'float' }) score: number;
+  @CreateDateColumn({ type: 'timestamp' }) scoreTimeStamp: Timestamp;
+
+  @ManyToOne(type => FactionEntity, factionName => factionName.factionId, {
+    onDelete: 'CASCADE',
+  })
+  faction: string;
+}
diff --git a/src/score/score.module.ts b/src/score/score.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c04486fc676fca0d7c6a38c74374e03e23a1008c
--- /dev/null
+++ b/src/score/score.module.ts
@@ -0,0 +1,27 @@
+import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
+
+import { ScoreController } from './score.controller';
+import { ScoreService } from './score.service';
+import { FactionEntity } from '../faction/faction.entity';
+import {
+  ObjectivePointEntity,
+  ObjectivePoint_HistoryEntity,
+} from '../game/game.entity';
+import { ScoreEntity } from './score.entity';
+import { NotificationModule } from '../notifications/notifications.module';
+
+@Module({
+  imports: [
+    TypeOrmModule.forFeature([
+      ScoreEntity,
+      ObjectivePointEntity,
+      ObjectivePoint_HistoryEntity,
+      FactionEntity,
+    ]),
+    NotificationModule,
+  ],
+  controllers: [ScoreController],
+  providers: [ScoreService],
+})
+export class ScoreModule {}
diff --git a/src/score/score.service.ts b/src/score/score.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dba8e6e79206322a4dffae937b5af6b2bdd89041
--- /dev/null
+++ b/src/score/score.service.ts
@@ -0,0 +1,119 @@
+import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+
+import { FactionEntity } from '../faction/faction.entity';
+import { ScoreDTO } from './score.dto';
+import {
+  ObjectivePoint_HistoryEntity,
+  ObjectivePointEntity,
+  GameEntity,
+} from '../game/game.entity';
+import { ScoreEntity } from './score.entity';
+import { NotificationGateway } from '../notifications/notifications.gateway';
+
+@Injectable()
+export class ScoreService {
+  constructor(
+    @InjectRepository(ScoreEntity)
+    private scoreRepository: Repository<ScoreEntity>,
+    @InjectRepository(ObjectivePointEntity)
+    private flagRepository: Repository<ObjectivePointEntity>,
+    @InjectRepository(ObjectivePoint_HistoryEntity)
+    private flagHistoryRepository: Repository<ObjectivePoint_HistoryEntity>,
+    @InjectRepository(FactionEntity)
+    private factionRepository: Repository<FactionEntity>,
+    private notificationGateway: NotificationGateway,
+  ) {}
+
+  async addScore(scoreData: ScoreDTO, gameId: GameEntity) {
+    // check if faction exists
+    const faction = await this.factionRepository.findOne({
+      factionId: scoreData.faction,
+    });
+    if (!faction) {
+      throw new HttpException('Faction was not found', HttpStatus.BAD_REQUEST);
+    }
+    // get the previous score and add it, if it exists
+    let lastScore = await this.scoreRepository.findOne({
+      where: { faction: scoreData.faction },
+      order: { scoreTimeStamp: 'DESC' },
+    });
+    if (lastScore) {
+      scoreData.score += lastScore.score;
+    }
+    // add the score for Faction
+    const newScore = await this.scoreRepository.create(scoreData);
+    await this.scoreRepository.insert(newScore);
+    return {
+      message: 'Score updated!',
+    };
+  }
+
+  async scoreTick(gameId) {
+    // get game's flagboxes
+    const flagboxes = await this.flagRepository.find({ game: gameId });
+    // create an array of DTOs for adding score
+    let scoreData = [];
+    await Promise.all(
+      flagboxes.map(async box => {
+        // get the newest entry in history
+        let current = await this.flagHistoryRepository.findOne({
+          where: { objective_point: box.objectivePointId },
+          relations: ['owner'],
+          order: { oP_HistoryTimestamp: 'DESC' },
+        });
+        // if result was found, add score to the owner
+        if (current.owner) {
+          let index = await scoreData.findIndex(
+            i => i.faction === current.owner.factionId,
+          );
+          index !== -1
+            ? await (scoreData[index]['score'] += box.objectivePointMultiplier)
+            : await scoreData.push({
+                score: box.objectivePointMultiplier,
+                faction: current.owner.factionId,
+              });
+        }
+      }),
+    );
+    scoreData.map(async data => {
+      await this.addScore(data, gameId);
+    });
+    this.notificationGateway.server.emit(gameId, { type: 'score-update' });
+    return {
+      message: 'Scores added',
+    };
+  }
+
+  async getScores(gameId: GameEntity) {
+    // find games factions
+    const factions = await this.factionRepository.find({
+      where: {game: gameId,},
+      relations: ['game'],
+    });
+    let scores = [];
+    await Promise.all(
+      factions.map(async factionNow => {
+        let score = await this.scoreRepository.findOne({
+          where: {faction: factionNow},
+          relations: ['faction'],
+          order: {scoreTimeStamp: 'DESC'},
+        });
+        //if score was found, put info to scores array
+        if (score.faction) {
+            let index = await scores.findIndex(
+              i => i.faction === score.faction,
+            );
+          scores.push(score);
+        }
+      }))
+      return scores;
+  }
+} //
+
+// Hae kaikki Objective pointit
+// aja map funktio pelin objective pointteihin
+// jokaisella objective point ID:llä hae historystä
+// relaatio, missä uusin timestamp
+// katso uusimmista history entrystä omistaja
diff --git a/src/shared/array-validation.ts b/src/shared/array-validation.ts
deleted file mode 100644
index 494ab42f06d0d067fcb115e6eebb63ef8dca2746..0000000000000000000000000000000000000000
--- a/src/shared/array-validation.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import {ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments} from "class-validator";
-import { Logger } from "@nestjs/common";
-
-// validates array length
-@ValidatorConstraint({ name: "arrayLength", async: true })
-export class ArrayLength implements ValidatorConstraintInterface {
-
-    validate(array: string[], args: ValidationArguments) {
-        Logger.log(array.length)
-        return array.length > args.constraints[0] && array.length < args.constraints[1]; // for async validations you must return a Promise<boolean> here
-    }
-
-    defaultMessage(args: ValidationArguments) { // here you can provide default error message if validation failed
-        return "Please input all passwords";
-    }
-
-}
\ No newline at end of file
diff --git a/src/shared/custom-validation.ts b/src/shared/custom-validation.ts
new file mode 100644
index 0000000000000000000000000000000000000000..13b96372e0b76a2897364baa15562edf383a2d81
--- /dev/null
+++ b/src/shared/custom-validation.ts
@@ -0,0 +1,52 @@
+import {
+  ValidatorConstraint,
+  ValidatorConstraintInterface,
+  ValidationArguments,
+  Validator,
+} from 'class-validator';
+
+// check if input is null or valid uuid
+@ValidatorConstraint({ name: 'uuid', async: true })
+export class Uuid implements ValidatorConstraintInterface {
+  validate(uuid: string, args: ValidationArguments) {
+    const validator = new Validator();
+    return validator.isUUID(uuid, '4') || uuid == null; // for async validations you must return a Promise<boolean> here
+  }
+
+  defaultMessage(args: ValidationArguments) {
+    return 'Not valid uuid';
+  }
+}
+
+// checks if role is valid
+@ValidatorConstraint({ name: 'roleValidation', async: true })
+export class RoleValidation implements ValidatorConstraintInterface {
+  validate(role: string, args: ValidationArguments) {
+    const validRoles = ['admin', 'soldier', 'factionleader'];
+    return validRoles.includes(role);
+  }
+
+  defaultMessage(args: ValidationArguments) {
+    return 'Not valid uuid';
+  }
+}
+
+// checks for valid JSON for center
+@ValidatorConstraint({ name: 'centerJSON', async: true })
+export class CenterJSON implements ValidatorConstraintInterface {
+  validate(center: JSON, args: ValidationArguments) {
+    const validator = new Validator();
+    return (
+      validator.isNumber(center['lat']) &&
+      validator.isNumber(center['lng']) &&
+      validator.min(center['lat'], -90) &&
+      validator.max(center['lat'], 90) &&
+      validator.min(center['lng'], -180) &&
+      validator.max(center['lng'], 180)
+    );
+  }
+
+  defaultMessage(args: ValidationArguments) {
+    return 'Error with center JSON';
+  }
+}
diff --git a/src/shared/roles.decorator.ts b/src/shared/guard.decorator.ts
similarity index 53%
rename from src/shared/roles.decorator.ts
rename to src/shared/guard.decorator.ts
index 0d14223c3ce5ee1002cf245fa16fd1b57749bae1..b299d6de913f54dd496c344f6dcdafd2942b2c9c 100644
--- a/src/shared/roles.decorator.ts
+++ b/src/shared/guard.decorator.ts
@@ -1,3 +1,6 @@
 import { SetMetadata } from '@nestjs/common';
 
-export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
\ No newline at end of file
+export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
+
+export const GameStates = (...states: string[]) =>
+  SetMetadata('states', states);
diff --git a/src/shared/http-error.filter.ts b/src/shared/http-error.filter.ts
index cafc414be633ac315931559cad3f4015eef0bf08..8a65068c4275c4a8d576da54b0340c17b6ac8cc4 100644
--- a/src/shared/http-error.filter.ts
+++ b/src/shared/http-error.filter.ts
@@ -1,23 +1,47 @@
-import { Catch, ExceptionFilter, HttpException, ArgumentsHost, Logger } from "@nestjs/common";
+import {
+  ExceptionFilter,
+  Catch,
+  ArgumentsHost,
+  Logger,
+  HttpException,
+  HttpStatus,
+} from '@nestjs/common';
 
 @Catch()
 export class HttpErrorFilter implements ExceptionFilter {
-    catch(exception: HttpException, host: ArgumentsHost) {
-        const ctx = host.switchToHttp();
-        const request = ctx.getRequest();
-        const response = ctx.getResponse();
-        const status = exception.getStatus();
+  catch(exception: HttpException, host: ArgumentsHost) {
+    const ctx = host.switchToHttp();
+    const response = ctx.getResponse();
+    const request = ctx.getRequest();
+    const status = exception.getStatus
+      ? exception.getStatus()
+      : HttpStatus.INTERNAL_SERVER_ERROR;
 
-        const errorResponse = {
-            code: status,
-            timestamp: new Date().toLocaleDateString(),
-            path: request.url,
-            method: request.method,
-            message: exception.message.error || exception.message || null,
-        };
+    const errorResponse = {
+      code: status,
+      timestamp: new Date().toLocaleDateString(),
+      path: request.url,
+      method: request.method,
+      message:
+        status !== HttpStatus.INTERNAL_SERVER_ERROR
+          ? exception.message.error || exception.message || null
+          : 'Internal server error',
+    };
 
-        Logger.error(`${request.method} ${request.url}`, JSON.stringify(errorResponse), "ExceptionFilter");
-
-        response.status(404).json({errorResponse});
+    if (status === HttpStatus.INTERNAL_SERVER_ERROR) {
+      Logger.error(
+        `${request.method} ${request.url}`,
+        exception.stack,
+        'ExceptionFilter',
+      );
+    } else {
+      Logger.error(
+        `${request.method} ${request.url}`,
+        JSON.stringify(errorResponse),
+        'ExceptionFilter',
+      );
     }
-}
\ No newline at end of file
+
+    response.status(status).json(errorResponse);
+  }
+}
diff --git a/src/shared/roles.guard.ts b/src/shared/roles.guard.ts
index 1f05fc90d4c008277e96d543f8112b4581a91c47..73693f9e1551da1b1b34056a665eb59c1211b3ef 100644
--- a/src/shared/roles.guard.ts
+++ b/src/shared/roles.guard.ts
@@ -18,7 +18,7 @@ export class RolesGuard implements CanActivate {
     private readonly reflector: Reflector,
     @InjectRepository(Game_PersonEntity)
     private game_PersonRepository: Repository<Game_PersonEntity>,
-    ) {}
+  ) {}
 
   async canActivate(context: ExecutionContext): Promise<boolean> {
     // get roles that are allowed access, identified by @Roles('role') decorators in controllers
@@ -27,9 +27,16 @@ export class RolesGuard implements CanActivate {
       return true;
     }
     const request = context.switchToHttp().getRequest();
-    const gameId = request.params.id
-    const user = await this.getUserObject(request.headers.authorization);
-    const role = await this.game_PersonRepository.findOne({person: user['id'], game: gameId})
+    // check for authorization header
+    if (!request.headers.authorization) {
+      return false;
+    }
+    const gameId = request.params.id;
+    request.user = await this.getUserObject(request.headers.authorization);
+    const role = await this.game_PersonRepository.findOne({
+      person: request.user['id'],
+      game: gameId,
+    });
     // check that the role matches the criteria and that token is valid for this game
     return role && roles.includes(role['role']);
   }
@@ -42,7 +49,7 @@ export class RolesGuard implements CanActivate {
     // get the token
     const token = auth.split(' ')[1];
     try {
-      return await jwt.verify(token, process.env.SECRET)
+      return await jwt.verify(token, process.env.SECRET);
     } catch (err) {
       const message = `Token error: ${err.message || err.name}`;
       throw new HttpException(message, HttpStatus.FORBIDDEN);
diff --git a/src/shared/states.guard.ts b/src/shared/states.guard.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9e85e94e40f92ed6b016e451c592a3025a684cad
--- /dev/null
+++ b/src/shared/states.guard.ts
@@ -0,0 +1,47 @@
+import {
+  Injectable,
+  CanActivate,
+  ExecutionContext,
+  HttpException,
+  HttpStatus,
+} from '@nestjs/common';
+import { Reflector } from '@nestjs/core';
+import { InjectRepository } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+
+import { GameEntity } from '../game/game.entity';
+
+@Injectable()
+export class StatesGuard implements CanActivate {
+  constructor(
+    private readonly reflector: Reflector,
+    @InjectRepository(GameEntity)
+    private gameRepository: Repository<GameEntity>,
+  ) {}
+
+  // Checks the state for gameId and grants access if it matches the criteria
+  // allowed states are CREATED, STARTED, PAUSED, ENDED
+  async canActivate(context: ExecutionContext): Promise<boolean> {
+    // get game states that are allowed access, identified by @GameStates('state') decorators in controllers
+    const states = this.reflector.get<string[]>('states', context.getHandler());
+    if (!states) {
+      return true;
+    }
+    const request = context.switchToHttp().getRequest();
+    const gameId = request.params.id;
+    const gameRef = await this.gameRepository.findOne({
+      id: gameId,
+    });
+    // check that the gameState matches the criteria
+    if (gameRef && states.includes(gameRef.state)) {
+      return true;
+    } else {
+      throw new HttpException(
+        `Game is set to ${
+          gameRef.state
+        }, operation only valid in states ${states.join(', ')}`,
+        HttpStatus.BAD_REQUEST,
+      );
+    }
+  }
+}
diff --git a/src/shared/validation.pipe.ts b/src/shared/validation.pipe.ts
index 27f078b8d48f7cf160aeac90ff50d4a080edf3d4..cff51f1b068b67886c29dd85587760a1fa016f1e 100644
--- a/src/shared/validation.pipe.ts
+++ b/src/shared/validation.pipe.ts
@@ -1,44 +1,65 @@
-
-import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException, HttpException, HttpStatus } from '@nestjs/common';
+import {
+  PipeTransform,
+  Injectable,
+  ArgumentMetadata,
+  HttpException,
+  HttpStatus,
+} from '@nestjs/common';
 import { validate } from 'class-validator';
 import { plainToClass } from 'class-transformer';
+import { AdvancedConsoleLogger } from 'typeorm';
 
 @Injectable()
 export class ValidationPipe implements PipeTransform<any> {
-    async transform(value: any, metadata: ArgumentMetadata) {
-
-        if (value instanceof Object && this.isEmpty(value)) {
-            throw new HttpException(
-                'Validation failed: No body submitted', HttpStatus.BAD_REQUEST
-            );
-        }
-
-        const { metatype } = metadata;
-        if (!metatype || !this.toValidate(metatype)) {
-            return value;
-        }
-        const object = plainToClass(metatype, value);
-        const errors = await validate(object);
-        if (errors.length > 0) {
-            throw new HttpException(`Validation failed: ${this.formatErrors(errors)}`, HttpStatus.BAD_REQUEST);
-        }
-        return value;
+  async transform(value: any, metadata: ArgumentMetadata) {
+    if (value instanceof Object && this.isEmpty(value)) {
+      throw new HttpException(
+        'Validation failed: No body submitted',
+        HttpStatus.BAD_REQUEST,
+      );
     }
 
-    private toValidate(metatype: Function): boolean {
-        const types: Function[] = [String, Boolean, Number, Array, Object];
-        return !types.includes(metatype);
+    const { metatype } = metadata;
+    if (!metatype || !this.toValidate(metatype)) {
+      return value;
     }
-
-    private formatErrors(errors: any[]) {
-        return errors.map(err => {
-            for (let property in err.constraints) {
-                return err.constraints[property]
-            }
-        }).join(", ");
+    const object = plainToClass(metatype, value);
+    const errors = await validate(object, {
+      whitelist: true,
+      forbidNonWhitelisted: true,
+    });
+    if (errors.length > 0) {
+      throw new HttpException(
+        `Validation failed: ${this.formatErrors(errors)}`,
+        HttpStatus.BAD_REQUEST,
+      );
     }
+    return value;
+  }
 
-    private isEmpty(value: any) {
-        return (Object.keys(value).length > 0) ? false : true;
+  private toValidate(metatype: Function): boolean {
+    const types: Function[] = [String, Boolean, Number, Array, Object];
+    return !types.includes(metatype);
+  }
+
+  private formatErrors(errors: any[]) {
+    return errors
+      .map(err => {
+        return this.returnError(err);
+      })
+      .join(', ');
+  }
+
+  private returnError(err) {
+    if (err['children'] !== undefined && err['children'].length != 0) {
+      return this.formatErrors(err['children']);
     }
-}
\ No newline at end of file
+    for (let property in err.constraints) {
+      return err.constraints[property];
+    }
+  }
+
+  private isEmpty(value: any) {
+    return Object.keys(value).length > 0 ? false : true;
+  }
+}
diff --git a/src/task/task.controller.ts b/src/task/task.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8283ba5bd2c4d7da4eb668ac6268d5165930e3f4
--- /dev/null
+++ b/src/task/task.controller.ts
@@ -0,0 +1,55 @@
+import {
+  Controller,
+  Post,
+  Body,
+  UsePipes,
+  Get,
+  Param,
+  Delete,
+} from '@nestjs/common';
+
+import { TaskService } from './task.service';
+import { CreateTaskDTO, EditTaskDTO, DeleteTaskDTO } from './task.dto';
+import { Roles } from '../shared/guard.decorator';
+import { ValidationPipe } from '../shared/validation.pipe';
+import { User } from '../user/user.decorator';
+
+@Controller('task')
+export class TaskController {
+  constructor(private taskService: TaskService) {}
+
+  // creates a new task if the user has admin role in the game
+  // :id is the id of the game
+  @Post('new-task/:id')
+  @Roles('admin')
+  @UsePipes(new ValidationPipe())
+  async newTask(@Param('id') id: string, @Body() task: CreateTaskDTO) {
+    return this.taskService.newTask(task);
+  }
+
+  // edits a created task if the user has admin role in the game
+  // :id is the id of the game
+  @Post('edit-task/:id')
+  @Roles('admin')
+  @UsePipes(new ValidationPipe())
+  async editTask(@Param('id') id: string, @Body() data: EditTaskDTO) {
+    return this.taskService.editTask(data);
+  }
+
+  // deletes a created task if the user has admin role in the game
+  // :id is the id of the game
+  @Delete('delete-task/:id')
+  @Roles('admin')
+  @UsePipes(new ValidationPipe())
+  async deleteTask(@Param('id') id: string, @Body() data: DeleteTaskDTO) {
+    return this.taskService.deleteTask(data);
+  }
+
+  // lists all the tasks for the game if the user has game_person entry
+  // :id is the id of the game
+  @Get('get-tasks/:id')
+  @Roles('soldier', 'factionleader', 'admin')
+  async fetchTasks(@User('id') person, @Param('id') id: string) {
+    return this.taskService.fetchTasks(person, id);
+  }
+}
diff --git a/src/task/task.dto.ts b/src/task/task.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a1576e7d12c9d9a6263b445fdba293fe94e8964a
--- /dev/null
+++ b/src/task/task.dto.ts
@@ -0,0 +1,43 @@
+import {
+  IsString,
+  Length,
+  IsBoolean,
+  Validate,
+  IsUUID,
+  Equals,
+} from 'class-validator';
+import { FactionEntity } from '../faction/faction.entity';
+import { GameEntity } from '../game/game.entity';
+import { Uuid } from '../shared/custom-validation';
+
+export class CreateTaskDTO {
+  @IsString()
+  @Length(3, 31)
+  taskName: string;
+  @IsString()
+  @Length(0, 255)
+  taskDescription: string;
+  @IsBoolean()
+  taskIsActive: boolean;
+  @Validate(Uuid)
+  faction: FactionEntity;
+  @Equals(null)
+  taskWinner: FactionEntity;
+  // faction unique id
+  @IsUUID('4')
+  taskGame: GameEntity;
+}
+
+export class EditTaskDTO {
+  @IsUUID('4')
+  taskId: string;
+  @IsUUID('4')
+  taskWinner: FactionEntity;
+  @IsUUID('4')
+  taskGame: GameEntity;
+}
+
+export class DeleteTaskDTO {
+  @IsUUID('4')
+  taskId: string;
+}
diff --git a/src/task/task.entity.ts b/src/task/task.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f1c1cf103fa4338a7f10d0305888d13c097d7a09
--- /dev/null
+++ b/src/task/task.entity.ts
@@ -0,0 +1,32 @@
+import {
+  PrimaryGeneratedColumn,
+  Column,
+  Entity,
+  ManyToOne,
+  JoinColumn,
+} from 'typeorm';
+
+import { FactionEntity } from '../faction/faction.entity';
+import { GameEntity } from '../game/game.entity';
+
+@Entity('Task')
+export class TaskEntity {
+  @PrimaryGeneratedColumn('uuid') taskId: string;
+  @Column({ type: 'text' }) taskName: string;
+  @Column({ type: 'text' }) taskDescription: string;
+  @Column({ type: 'bool' }) taskIsActive: boolean;
+
+  @ManyToOne(type => FactionEntity, faction => faction.factionId, {
+    onDelete: 'CASCADE',
+  })
+  faction: FactionEntity;
+  @ManyToOne(type => FactionEntity, faction => faction.factionId, {
+    onDelete: 'CASCADE',
+  })
+  taskWinner: FactionEntity;
+  @ManyToOne(type => GameEntity, game => game.id, {
+    onDelete: 'CASCADE',
+  })
+  @JoinColumn({ name: 'taskGame' })
+  taskGame: GameEntity;
+}
diff --git a/src/task/task.module.ts b/src/task/task.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..66d5ac5fce93d8447317343283a84b5002755ab6
--- /dev/null
+++ b/src/task/task.module.ts
@@ -0,0 +1,19 @@
+import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
+
+import { TaskService } from './task.service';
+import { TaskController } from './task.controller';
+import { TaskEntity } from './task.entity';
+import { FactionEntity } from '../faction/faction.entity';
+import { Game_PersonEntity } from '../game/game.entity';
+import { NotificationModule } from '../notifications/notifications.module';
+
+@Module({
+  imports: [
+    TypeOrmModule.forFeature([TaskEntity, FactionEntity, Game_PersonEntity]),
+    NotificationModule,
+  ],
+  controllers: [TaskController],
+  providers: [TaskService],
+})
+export class TaskModule {}
diff --git a/src/task/task.service.ts b/src/task/task.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d79338e0d21e9ce741c67d4bf94b89ba64e4c9c9
--- /dev/null
+++ b/src/task/task.service.ts
@@ -0,0 +1,111 @@
+import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
+import { Repository } from 'typeorm';
+import { InjectRepository } from '@nestjs/typeorm';
+
+import { TaskEntity } from './task.entity';
+import { CreateTaskDTO, EditTaskDTO, DeleteTaskDTO } from './task.dto';
+import { FactionEntity } from '../faction/faction.entity';
+import { Game_PersonEntity } from '../game/game.entity';
+import { NotificationGateway } from '../notifications/notifications.gateway';
+
+@Injectable()
+export class TaskService {
+  constructor(
+    @InjectRepository(TaskEntity)
+    private taskRepository: Repository<TaskEntity>,
+    @InjectRepository(FactionEntity)
+    private factionRepository: Repository<FactionEntity>,
+    @InjectRepository(Game_PersonEntity)
+    private gamePersonRepository: Repository<Game_PersonEntity>,
+    private notificationGateway: NotificationGateway,
+  ) {}
+
+  async newTask(task: CreateTaskDTO) {
+    // check if is not null, check that the faction exists in the game
+    if (
+      task.faction != null &&
+      !(await this.factionRepository.findOne({
+        factionId: task.faction.toString(),
+        game: task.taskGame,
+      }))
+    ) {
+      throw new HttpException('Faction not found', HttpStatus.BAD_REQUEST);
+    }
+    const createdTask = await this.taskRepository.create(task);
+    await this.taskRepository.insert(createdTask);
+    // notify subscribers about a new task
+    // if faction was set it notifies only faction members, else everyone
+    this.notificationGateway.server.emit(
+      task.faction != null ? task.faction.toString() : task.taskGame.toString(),
+      { type: 'task-update' },
+    );
+    return {
+      message: 'Task added',
+    };
+  }
+
+  async editTask(data: EditTaskDTO) {
+    const task = await this.taskRepository.findOne(data.taskId);
+    // checks if task is already closed
+    if (!task.taskIsActive) {
+      throw new HttpException('Task is not active', HttpStatus.BAD_REQUEST);
+    }
+    // checks if faction is valid
+    if (
+      !(await this.factionRepository.findOne({
+        factionId: data.taskWinner.toString(),
+        game: data.taskGame,
+      }))
+    ) {
+      throw new HttpException('Faction not found', HttpStatus.BAD_REQUEST);
+    }
+    task.taskWinner = data.taskWinner;
+    task.taskIsActive = false;
+    await this.taskRepository.save(task);
+    return {
+      message: 'Task updated and closed',
+    };
+  }
+
+  async deleteTask(data: DeleteTaskDTO) {
+    const task = await this.taskRepository.findOne({ taskId: data.taskId });
+    if (task) {
+      await this.taskRepository.delete({ taskId: task.taskId });
+      return {
+        message: 'Task deleted',
+      };
+    }
+    throw new HttpException('Task not found', HttpStatus.BAD_REQUEST);
+  }
+
+  async fetchTasks(user, taskGame) {
+    const gamePerson = await this.gamePersonRepository.findOne({
+      where: {
+        person: user,
+        game: taskGame,
+      },
+      relations: ['faction'],
+    });
+    if (gamePerson.role == 'admin') {
+      return await this.taskRepository.find({
+        where: { taskGame: taskGame },
+        relations: ['faction', 'taskWinner'],
+      });
+    } else {
+      return await this.taskRepository.find({
+        relations: ['faction', 'taskWinner'],
+        where: [
+          {
+            taskGame: taskGame,
+            faction: gamePerson.faction.factionId,
+          },
+          {
+            taskGame: taskGame,
+            faction: null,
+          },
+        ],
+        order: { taskIsActive: 'DESC' },
+      });
+    }
+  }
+}
diff --git a/src/tracking/geo.dto.ts b/src/tracking/geo.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..352faf704db72912a548734185d277253d67c789
--- /dev/null
+++ b/src/tracking/geo.dto.ts
@@ -0,0 +1,14 @@
+import { IsNumber, Min, Max, Allow } from 'class-validator';
+
+export class GeoDTO {
+  @IsNumber()
+  @Min(-90)
+  @Max(90)
+  lat: number;
+  @IsNumber()
+  @Min(-180)
+  @Max(180)
+  lng: number;
+  @Allow()
+  time: number;
+}
diff --git a/src/tracking/tracking.controller.ts b/src/tracking/tracking.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ca0e79ee5195503f61d827dbc170474e66fd1bad
--- /dev/null
+++ b/src/tracking/tracking.controller.ts
@@ -0,0 +1,42 @@
+import {
+  Controller,
+  Post,
+  Param,
+  UseGuards,
+  UsePipes,
+  Body,
+  Get,
+} from '@nestjs/common';
+
+import { TrackingService } from './tracking.service';
+import { TrackingDTO } from './tracking.dto';
+import { User } from '../user/user.decorator';
+import { Roles, GameStates } from '../shared/guard.decorator';
+import { ValidationPipe } from '../shared/validation.pipe';
+import { GeoDTO } from './geo.dto';
+
+@Controller('tracking')
+export class TrackingController {
+  constructor(private trackingservice: TrackingService) {}
+
+  // inserts tracking data to the database
+  // :id is the id of the game
+  @Post('location/:id')
+  @Roles('soldier')
+  @GameStates('STARTED')
+  @UsePipes(new ValidationPipe())
+  async trackLocation(
+    @User('id') userId,
+    @Param('id') id,
+    @Body() trackdata: GeoDTO,
+  ) {
+    return this.trackingservice.trackLocation(userId, id, trackdata);
+  }
+
+  @Get('players/:id')
+  @Roles('admin', 'factionleader')
+  @GameStates('STARTED', 'PAUSED')
+  async getPlayerLocations(@User('id') userId, @Param('id') gameId) {
+    return this.trackingservice.getPlayers(userId, gameId);
+  }
+}
diff --git a/src/tracking/tracking.dto.ts b/src/tracking/tracking.dto.ts
new file mode 100644
index 0000000000000000000000000000000000000000..81cc71597fa93910cb195b1fd4e30f38c62c1f05
--- /dev/null
+++ b/src/tracking/tracking.dto.ts
@@ -0,0 +1,10 @@
+import { Game_PersonEntity } from '../game/game.entity';
+import { Allow, ValidateNested } from 'class-validator';
+import { GeoDTO } from './geo.dto';
+import { Type } from 'class-transformer';
+
+export class TrackingDTO {
+  @ValidateNested()
+  @Type(() => GeoDTO)
+  data: GeoDTO;
+}
diff --git a/src/tracking/tracking.entity.ts b/src/tracking/tracking.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c2699a09388ce8ad47c7119b46f4614fa52b34ec
--- /dev/null
+++ b/src/tracking/tracking.entity.ts
@@ -0,0 +1,19 @@
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
+import { Game_PersonEntity, GameEntity } from '../game/game.entity';
+import { FactionEntity } from 'src/faction/faction.entity';
+import { GeoDTO } from './geo.dto';
+
+@Entity('Tracking')
+export class TrackingEntity {
+  @PrimaryGeneratedColumn('uuid') id: string;
+  @Column({ type: 'json', nullable: true }) data: GeoDTO[];
+
+  @ManyToOne(type => Game_PersonEntity, person => person.gamepersonId, {
+    onDelete: 'CASCADE',
+  })
+  gamepersonId: Game_PersonEntity;
+  @ManyToOne(type => FactionEntity, faction => faction.factionId)
+  faction: FactionEntity;
+  @ManyToOne(type => GameEntity, game => game.id)
+  game: GameEntity;
+}
diff --git a/src/tracking/tracking.module.ts b/src/tracking/tracking.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..45b167fc526ab41addbb87575518c9acae884482
--- /dev/null
+++ b/src/tracking/tracking.module.ts
@@ -0,0 +1,14 @@
+import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
+
+import { TrackingController } from './tracking.controller';
+import { TrackingService } from './tracking.service';
+import { TrackingEntity } from './tracking.entity';
+import { Game_PersonEntity } from '../game/game.entity';
+
+@Module({
+  imports: [TypeOrmModule.forFeature([TrackingEntity, Game_PersonEntity])],
+  controllers: [TrackingController],
+  providers: [TrackingService],
+})
+export class TrackingModule {}
diff --git a/src/tracking/tracking.service.ts b/src/tracking/tracking.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9941256dde52240d7c90b45d61b7b32ef4e1c242
--- /dev/null
+++ b/src/tracking/tracking.service.ts
@@ -0,0 +1,102 @@
+import { Injectable, HttpStatus, HttpException } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+
+import { Game_PersonEntity } from '../game/game.entity';
+import { TrackingEntity } from './tracking.entity';
+import { TrackingDTO } from './tracking.dto';
+import { FactionEntity } from '../faction/faction.entity';
+import { NotificationGateway } from 'src/notifications/notifications.gateway';
+import { GeoDTO } from './geo.dto';
+
+@Injectable()
+export class TrackingService {
+  constructor(
+    @InjectRepository(TrackingEntity)
+    private trackingrepository: Repository<TrackingEntity>,
+    @InjectRepository(Game_PersonEntity)
+    private gamepersonrepository: Repository<Game_PersonEntity>,
+  ) {}
+
+  async trackLocation(personId, gameId, trackdata: GeoDTO) {
+    // find player
+    let gameperson = await this.gamepersonrepository.findOne({
+      where: { game: gameId, person: personId },
+      relations: ['faction'],
+    });
+    if (!gameperson) {
+      throw new HttpException(
+        'You have not joined this game',
+        HttpStatus.BAD_REQUEST,
+      );
+    }
+    let trackedperson = await this.trackingrepository.findOne({
+      gamepersonId: gameperson,
+    });
+
+    // if player has pushed tracking data, update entry
+    if (trackedperson) {
+      trackdata['time'] = Date.now();
+      //add coordinates
+      trackedperson.data.push(trackdata);
+      //add timestamp
+      await this.trackingrepository.save(trackedperson);
+      return { code: 201, message: 'Location updated!' };
+    } else {
+      // first entry will be empty
+      trackdata['time'] = Date.now();
+      // initialize data
+      trackedperson = await this.trackingrepository.create(trackedperson);
+      trackedperson.data = [trackdata];
+      trackedperson.faction = gameperson.faction;
+      trackedperson.game = gameId;
+      trackedperson.gamepersonId = gameperson;
+      await this.trackingrepository.save(trackedperson);
+
+      return { code: 201, message: 'Entry Created!' };
+    }
+  }
+
+  // get player data while game is running
+  async getPlayers(userId, gameId) {
+    // get gameperson
+    const gameperson = await this.gamepersonrepository.findOne({
+      where: { person: userId, game: gameId },
+      relations: ['faction'],
+    });
+
+    let playerdata;
+    // get playerdata
+    if (gameperson.faction) {
+      playerdata = await this.trackingrepository.find({
+        where: { faction: gameperson.faction },
+        relations: ['faction', 'gamepersonId'],
+      });
+    } else {
+      playerdata = await this.trackingrepository.find({
+        where: { game: gameId },
+        relations: ['faction', 'gamepersonId'],
+      });
+    }
+
+    // parse data
+    const currentdata = await Promise.all(
+      playerdata.map(async player => {
+        return {
+          gamepersonId: player['gamepersonId']['gamepersonId'],
+          gamepersonRole: player['gamepersonId']['role'],
+          factionId: player['faction']['factionId'],
+          coordinates: player['data'].pop(),
+        };
+      }),
+    );
+
+    return currentdata;
+  }
+
+  private async mapFunction(data): Promise<Number> {
+    return await data.map(type => {
+      return type;
+    });
+  }
+}
diff --git a/src/user/user.controller.spec.ts b/src/user/user.controller.spec.ts
deleted file mode 100644
index 95e4e6222d74fb868ba0480ec5da337c636359c5..0000000000000000000000000000000000000000
--- a/src/user/user.controller.spec.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Test, TestingModule } from '@nestjs/testing';
-import { UserController } from './user.controller';
-
-describe('User Controller', () => {
-  let controller: UserController;
-
-  beforeEach(async () => {
-    const module: TestingModule = await Test.createTestingModule({
-      controllers: [UserController],
-    }).compile();
-
-    controller = module.get<UserController>(UserController);
-  });
-
-  it('should be defined', () => {
-    expect(controller).toBeDefined();
-  });
-});
diff --git a/src/user/user.entity.ts b/src/user/user.entity.ts
index 1e44121e0eed81e1a1b7a7f35e9a95e557c89e5e..716020ae49d675641863a1711e424b85dbd67608 100644
--- a/src/user/user.entity.ts
+++ b/src/user/user.entity.ts
@@ -7,13 +7,18 @@ import {
 } from 'typeorm';
 import * as bcrypt from 'bcryptjs';
 import * as jwt from 'jsonwebtoken';
+
 import { Game_PersonEntity } from '../game/game.entity';
+import { Exclude } from 'class-transformer';
 
 @Entity('Person')
 export class PersonEntity {
   @PrimaryGeneratedColumn('uuid') id: string;
   @Column({ type: 'text', unique: true }) name: string;
-  @Column('text') password: string;
+
+  @Exclude()
+  @Column('text')
+  password: string;
 
   @OneToMany(type => Game_PersonEntity, game_persons => game_persons.person)
   game_persons: Game_PersonEntity[];
@@ -30,12 +35,6 @@ export class PersonEntity {
     return { name, token };
   }
 
-  // returns username and the id
-  nameObject() {
-    const { id, name } = this;
-    return { id, name };
-  }
-
   async comparePassword(attempt: string) {
     return await bcrypt.compareSync(attempt, this.password);
   }
diff --git a/src/user/user.service.spec.ts b/src/user/user.service.spec.ts
deleted file mode 100644
index 873de8ac4d8e77fc827e4f3939f0068391a3800c..0000000000000000000000000000000000000000
--- a/src/user/user.service.spec.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Test, TestingModule } from '@nestjs/testing';
-import { UserService } from './user.service';
-
-describe('UserService', () => {
-  let service: UserService;
-
-  beforeEach(async () => {
-    const module: TestingModule = await Test.createTestingModule({
-      providers: [UserService],
-    }).compile();
-
-    service = module.get<UserService>(UserService);
-  });
-
-  it('should be defined', () => {
-    expect(service).toBeDefined();
-  });
-});
diff --git a/tests/valid_registration.robot b/tests/00_valid_registration.robot
similarity index 78%
rename from tests/valid_registration.robot
rename to tests/00_valid_registration.robot
index f62f83add9b43e2e855b85d2191bac366c002fc9..afca0e6e04b31d625a78852f7af513dae811e0b7 100644
--- a/tests/valid_registration.robot
+++ b/tests/00_valid_registration.robot
@@ -7,7 +7,8 @@ Suite Teardown  Close Browser
 *** Test Cases ***
 Registration Process
     Open Registration
-    Generate Username       12
-    Generate Password       6
+    Generate Valid Username
+    Input Valid Username
+    Input Valid Password
     Submit Credentials Registration
     Log Out
diff --git a/tests/valid_login.robot b/tests/01_valid_login.robot
similarity index 81%
rename from tests/valid_login.robot
rename to tests/01_valid_login.robot
index 01d1140d5ac71edae110307c7b7dbaac11373325..b31ec3b335b0a19f5227c1a8544c4e2ceb105a38 100644
--- a/tests/valid_login.robot
+++ b/tests/01_valid_login.robot
@@ -7,8 +7,8 @@ Resource        resource.robot
 Valid Login
     Open Browser To Login Page
     Open Login
-    Input Username      ville
-    Input Password      koira
+    Input Username      ${VALID USER}
+    Input Password      ${VALID PASSWORD}
     Submit Credentials Login
     Wait For Log Out Button To Appear
     Log Out
diff --git a/tests/02_invalid_registration.robot b/tests/02_invalid_registration.robot
new file mode 100644
index 0000000000000000000000000000000000000000..2c4670a94617a1e3a157b26abc748457e00b4dc1
--- /dev/null
+++ b/tests/02_invalid_registration.robot
@@ -0,0 +1,49 @@
+*** Settings ***
+Documentation    A test suite for invalid registration.
+Resource        resource.robot
+Suite Setup     Open Browser To Login Page
+Suite Teardown  Close Browser
+Test Template   Registration With Invalid Options Should Fail
+
+*** Variables ***
+${ge_u} =       Generate Username
+${ge_p} =       Generate Password
+${ge_vp} =      Generate Differing Password
+
+*** Test Cases ***
+Short Username                          ${ge_u}         2           ${ge_p}     32      ${SHORT_U}
+Long Username                           ${ge_u}         32          ${ge_p}     32      ${LONG_U}
+Short Password                          ${ge_u}         31          ${ge_p}     2       ${SHORT_P}
+Long Password                           ${ge_u}         31          ${ge_p}     256     ${LONG_P}
+Short Username/Password                 ${ge_u}         2           ${ge_p}     2       ${SHORT_UP}
+Long Username/Password                  ${ge_u}         32          ${ge_p}     256     ${LONG_UP}
+Short Username And Long Password        ${ge_u}         2           ${ge_p}     256     ${SU_LP}
+Long Username And Short Password        ${ge_u}         32          ${ge_p}     2       ${LU_SP}
+#Differing Password
+#Existing Account Correct Password
+#Existing Account New Password
+Empty Username And Password             ${ge_u}         0           ${ge_p}     0       ${SHORT_UP}
+
+
+*** Keywords ***
+Registration With Invalid Options Should Fail
+    [Arguments]     ${gene_usern}       ${GNUM_U}       ${gene_passwords}       ${GNUM_P}       ${error_text}
+    Open Registration
+    Run Keyword     ${gene_usern}           ${GNUM_U}
+    Run Keyword     ${gene_passwords}       ${GNUM_P}
+    Submit Credentials Registration
+    Registration Should Have Failed     ${error_text}
+    Close Registration Screen
+
+Registration Should Have Failed        #Checks the error message.
+    [Arguments]     ${error_text}
+    Element Text Should Be      css=h2      ${error_text}
+    #Title Should Be    Error Page      #If there's going to be an error page.
+
+Differing Password
+    Open Registration
+    Generate Username       31
+    Generate Differing Password     8
+    Submit Credentials Registration
+    #Registration Should Have Failed
+    Close Registration Screen
\ No newline at end of file
diff --git a/tests/invalid_login.robot b/tests/invalid_login.robot
deleted file mode 100644
index 287bb6699b6dc037350e903dfc97042e8910b703..0000000000000000000000000000000000000000
--- a/tests/invalid_login.robot
+++ /dev/null
@@ -1,29 +0,0 @@
-*** Settings ***
-Documentation    A test suite for invalid login.
-Resource        resource.robot
-Suite Setup     Open Browser To Login Page
-Suite Teardown  Close Browser
-Test Template      Login With Invalid Credentials Should Fail
-*** Test Cases ***
-Invalid Username                 invalid        ${VALID PASSWORD}       ${INVALID_U}
-Invalid Password                 ${VALID USER}    invalid               ${INVALID_P}
-Invalid Username And Password    invalid          whatever              ${INVALID_U}
-Empty Username                   ${EMPTY}         ${VALID PASSWORD}     ${SHORT_U}
-Empty Password                   ${VALID USER}    ${EMPTY}              ${SHORT_P}
-Empty Username And Password      ${EMPTY}         ${EMPTY}              ${SHORT_UP}
-
-*** Keywords ***
-Login With Invalid Credentials Should Fail
-    [Arguments]    ${username}    ${password}   ${error_text}
-    Open Login
-    Input Username    ${username}
-    Input Password    ${password}
-    Submit Credentials Login
-    Login Should Have Failed    ${error_text}
-    Close Login Screen
-
-Login Should Have Failed        #Checks the error message.
-    [Arguments]     ${error_text}
-    Element Text Should Be      css=h2      ${error_text}
-    #Title Should Be    Error Page      #If there's going to be an error page.
-
diff --git a/tests/resource.robot b/tests/resource.robot
index 94829d0a25dc28045c03b38b702752bc6dd29386..0aa3c238a2396ae7a2127fb0994cf7e90d6b10dc 100644
--- a/tests/resource.robot
+++ b/tests/resource.robot
@@ -1,121 +1,96 @@
 *** Settings ***
-Documentation       A resource file with reusable keywords and variables.
-Library     SeleniumLibrary    run_on_failure=nothing
-Library     String
-
+Documentation    A resource file with reusable keywords and variables.
+Library   SeleniumLibrary  run_on_failure=nothing
+Library   String
 *** Variables ***
-${SERVER}       %{SITE_URL}
-${BROWSER}      firefox
-${DELAY}        0.5
-${VALID USER}           ville
-${VALID PASSWORD}       koira
-${LOGIN URL}        http://${SERVER}/
-${WELCOME URL}      #You can use this if there's a different page after login page.
-${LOC_USER}           id=registerUsernameInput            #Generated username.
-${LOC_PASSWORD}       id=registerPasswordInput            #Generated password first time.
-${LOC_PASSWORD2}      id=registerPasswordVerifyInput      #Generated password verify.
-${ZOOMIN}           //*[@id="root"]/div/div[1]/div[2]/div[2]/div[1]/a[1]        #Zoom in button location
-${ZOOMOUT}          //*[@id="root"]/div/div[1]/div[2]/div[2]/div[1]/a[2]       #Zoom out button location
-${INVALID_U}        User does not exist
-${INVALID_P}        Invalid password
-${SHORT_P}          Validation failed: password must be longer than or equal to 3 characters
-${SHORT_U}          Validation failed: name must be longer than or equal to 3 characters
-${SHORT_UP}         Validation failed: name must be longer than or equal to 3 characters, password must be longer than or equal to 3 characters
-${LONG_U}           Validation failed: name must be shorter than or equal to 31 characters
-${LONG_P}           Validation failed: password must be shorter than or equal to 255 characters
-${LONG_UP}          Validation failed: name must be shorter than or equal to 31 characters, password must be shorter than or equal to 255 characters
-${SU_LP}            Validation failed: name must be longer than or equal to 3 characters, password must be shorter than or equal to 255 characters
-${LU_SP}            Validation failed: name must be shorter than or equal to 31 characters, password must be longer than or equal to 3 characters
-
+${SERVER}    %{SITE_URL}
+${BROWSER}   ff
+${DELAY}    0.5
+${VALID PASSWORD} =   koira
+${LOGIN URL}    https://${SERVER}/
+${WELCOME URL}   #You can use this if there's a different page after login page.
+${LOC_USER}      id=registerUsernameInput      #Generated username.
+${LOC_PASSWORD}    id=registerPasswordInput      #Generated password first time.
+${LOC_PASSWORD2}   id=registerPasswordVerifyInput   #Generated password verify.
+${ZOOMIN}      //*[@id="root"]/div/div[1]/div[2]/div[2]/div[1]/a[1]    #Zoom in button location
+${ZOOMOUT}     //*[@id="root"]/div/div[1]/div[2]/div[2]/div[1]/a[2]    #Zoom out button location
+${INVALID_U}    User does not exist
+${INVALID_P}    Invalid password
+${SHORT_P}     Validation failed: password must be longer than or equal to 3 characters
+${SHORT_U}     Validation failed: name must be longer than or equal to 3 characters
+${SHORT_UP}     Validation failed: name must be longer than or equal to 3 characters, password must be longer than or equal to 3 characters
+${LONG_U}      Validation failed: name must be shorter than or equal to 31 characters
+${LONG_P}      Validation failed: password must be shorter than or equal to 255 characters
+${LONG_UP}     Validation failed: name must be shorter than or equal to 31 characters, password must be shorter than or equal to 255 characters
+${SU_LP}      Validation failed: name must be longer than or equal to 3 characters, password must be shorter than or equal to 255 characters
+${LU_SP}      Validation failed: name must be shorter than or equal to 31 characters, password must be longer than or equal to 3 characters
 *** Keywords ***
 #Valid Login
 Open Browser To Login Page
-    Open Browser        ${LOGIN URL}      ${BROWSER}
-    Maximize Browser Window
-    Set Selenium Speed      ${DELAY}
-    Login Page Should be Open
-
+  Open Browser    ${LOGIN URL}   ${BROWSER}
+  Maximize Browser Window
+  Set Selenium Speed   ${DELAY}
+  Login Page Should be Open
 Login Page Should be Open
-    Title Should Be     React App
-
-
+  Title Should Be   React App
 Go To Login Page
-    Go To       ${LOGIN URL}
-    Login Page Should be Open
-
+  Go To    ${LOGIN URL}
+  Login Page Should be Open
 Open Login
-    Click Button       id=loginButton
-
+  Click Button    id=loginButton
 Input Username
-    [Arguments]     ${username}
-    Input Text      id=loginUsernameInput      ${username}
-
+  [Arguments]   ${username}
+  Input Text   id=loginUsernameInput   ${username}
 Input Password
-    [Arguments]     ${password}
-    Input Text      id=loginPasswordInput        ${password}
-
+  [Arguments]   ${password}
+  Input Text   id=loginPasswordInput    ${password}
 Submit Credentials Login
-    Click Button        id=submitLoginButton
-
-Welcome Page Should Be Open     #You can use this if there's a different page after login page.
-    Location Should Be      ${WELCOME URL}
-
+  Click Button    id=submitLoginButton
+Welcome Page Should Be Open   #You can use this if there's a different page after login page.
+  Location Should Be   ${WELCOME URL}
 Log Out
-    Click Button        id=logoutButton
-
+  Click Button    id=logoutButton
 Close Login Screen
-    Click Element        id=closeLoginFormX
-
+  Click Element    id=closeLoginFormX
 Wait For Log Out Button To Appear
-    Wait Until Page Contains Element        id=logoutButton      1
-
+  Wait Until Page Contains Element    id=logoutButton   1
 #Registration
 Open Registration
-    Click Button        id=registerButton
-
-
-Generate Username       #Generates a random username        lenght=8     chars=[LETTERS][NUMBERS]
-    [Arguments]     ${GNUM_U}
-    ${GENE_username} =   Generate Random String      ${GNUM_U}       [LETTERS][NUMBERS]
-    Input Text      ${LOC_USER}        ${GENE_username}
-
-Generate Password       #Generates a random password        lenght=8     chars=[LETTERS][NUMBERS]
-    [Arguments]     ${GNUM_P}
-    ${GENE_password} =   Generate Random String      ${GNUM_P}       [LETTERS][NUMBERS]
-    Input Text      ${LOC_PASSWORD}        ${GENE_password}
-    Input Text      ${LOC_PASSWORD2}        ${GENE_password}
-
+  Click Button    id=registerButton
+Generate Valid Username
+  ${GENE_username} =   Generate Random String   12    [LETTERS][NUMBERS]
+  Set Global Variable  ${VALID USER}  ${GENE_username}
+Input Valid Username
+  Input Text   ${LOC_USER}    ${VALID USER}
+Input Valid Password
+  Input Text   ${LOC_PASSWORD}    ${VALID PASSWORD}
+  Input Text   ${LOC_PASSWORD2}    ${VALID PASSWORD}
+Generate Username    #Generates a random username    lenght=8   chars=[LETTERS][NUMBERS]
+  [Arguments]   ${GNUM_U}
+  ${GENE_username} =  Generate Random String   ${GNUM_U}    [LETTERS][NUMBERS]
+  Input Text   ${LOC_USER}    ${GENE_username}
+Generate Password    #Generates a random password    lenght=8   chars=[LETTERS][NUMBERS]
+  [Arguments]   ${GNUM_P}
+  ${GENE_password} =  Generate Random String   ${GNUM_P}    [LETTERS][NUMBERS]
+  Input Text   ${LOC_PASSWORD}    ${GENE_password}
+  Input Text   ${LOC_PASSWORD2}    ${GENE_password}
 Generate Differing Password
-    [Arguments]     ${GNUM_VP}
-    ${GENE_dpassword} =     Generate Random String      ${GNUM_VP}      [LETTERS][NUMBERS]
-    ${GENE_dpassword2} =     Generate Random String      ${GNUM_VP}      [LETTERS][NUMBERS]
-    Input Text      ${LOC_PASSWORD}      ${GENE_dpassword}
-    Input Text      ${LOC_PASSWORD2}      ${GENE_dpassword2}
-
+  [Arguments]   ${GNUM_VP}
+  ${GENE_dpassword} =   Generate Random String   ${GNUM_VP}   [LETTERS][NUMBERS]
+  ${GENE_dpassword2} =   Generate Random String   ${GNUM_VP}   [LETTERS][NUMBERS]
+  Input Text   ${LOC_PASSWORD}   ${GENE_dpassword}
+  Input Text   ${LOC_PASSWORD2}   ${GENE_dpassword2}
 Submit Credentials Registration
-    Click Button        id=submitRegisterButton
-
+  Click Button    id=submitRegisterButton
 Close Registration Screen
-    Click Element       id=closeRegisterFormX
-
+  Click Element    id=closeRegisterFormX
 #Zoom frontpage
 Wait For Zoom Button To Appear
-    Wait Until Page Contains Element        //*[@id="root"]/div/div[1]/div[2]/div[2]/div[1]/a[1]       1
-
+  Wait Until Page Contains Element    //*[@id="root"]/div/div[1]/div[2]/div[2]/div[1]/a[1]    1
 Zoom In On Frontpage
-    Repeat Keyword          3 times         Click Element      ${ZOOMIN}
-
-
+  Repeat Keyword     3 times     Click Element   ${ZOOMIN}
 Zoom Out On Frontpage
-    Repeat Keyword          3 times         Click Element       ${ZOOMOUT}
-
-
-Move Around On The Map Frontpage            #en saanut toimimaan
-    #Press Key       //*[@id="root"]/div/div[1]/div[1]       ARROW_LEFT
-    Press Combination       Key.
-
-
-
-
-
-
+  Repeat Keyword     3 times     Click Element    ${ZOOMOUT}
+Move Around On The Map Frontpage      #en saanut toimimaan
+  #Press Key    //*[@id="root"]/div/div[1]/div[1]    ARROW_LEFT
+  Press Combination    Key.
\ No newline at end of file