diff --git a/src/main/java/de/thm/arsnova/controller/CommentController.java b/src/main/java/de/thm/arsnova/controller/CommentController.java
index f05f4e85f0f0220cdf450e542672b4d32dc7cc01..d4e8047d5b53fb3f6d18db2e6649a990dae0d0bc 100644
--- a/src/main/java/de/thm/arsnova/controller/CommentController.java
+++ b/src/main/java/de/thm/arsnova/controller/CommentController.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.controller;
 
-import de.thm.arsnova.entities.migration.v2.Comment;
+import de.thm.arsnova.entities.Comment;
 import de.thm.arsnova.entities.migration.v2.CommentReadingCount;
 import de.thm.arsnova.exceptions.BadRequestException;
 import de.thm.arsnova.services.CommentService;
diff --git a/src/main/java/de/thm/arsnova/controller/ContentController.java b/src/main/java/de/thm/arsnova/controller/ContentController.java
index 848797f3ddb3b995e5431c19c17cbd49e6bcf736..87cb2f44ac8ed57ca3cd643117104231ee2c9306 100644
--- a/src/main/java/de/thm/arsnova/controller/ContentController.java
+++ b/src/main/java/de/thm/arsnova/controller/ContentController.java
@@ -17,14 +17,16 @@
  */
 package de.thm.arsnova.controller;
 
-import de.thm.arsnova.util.PaginationListDecorator;
-import de.thm.arsnova.entities.migration.v2.Answer;
-import de.thm.arsnova.entities.migration.v2.Content;
+import de.thm.arsnova.entities.Answer;
+import de.thm.arsnova.entities.Content;
 import de.thm.arsnova.exceptions.BadRequestException;
 import de.thm.arsnova.exceptions.ForbiddenException;
 import de.thm.arsnova.exceptions.NoContentException;
 import de.thm.arsnova.exceptions.NotFoundException;
+import de.thm.arsnova.exceptions.NotImplementedException;
 import de.thm.arsnova.services.ContentService;
+import de.thm.arsnova.services.TimerService;
+import de.thm.arsnova.util.PaginationListDecorator;
 import de.thm.arsnova.web.DeprecatedApi;
 import de.thm.arsnova.web.Pagination;
 import io.swagger.annotations.Api;
@@ -56,6 +58,9 @@ public class ContentController extends PaginationController {
 	@Autowired
 	private ContentService contentService;
 
+	@Autowired
+	private TimerService timerService;
+
 	@ApiOperation(value = "Get question with provided question Id",
 			nickname = "getQuestion")
 	@ApiResponses(value = {
@@ -125,11 +130,7 @@ public class ContentController extends PaginationController {
 			@RequestParam(value = "fcImage", defaultValue = "false", required = false) final boolean fcImage
 			) {
 
-		if (fcImage) {
-			return contentService.getQuestionFcImage(questionId);
-		} else {
-			return contentService.getQuestionImage(questionId);
-		}
+		throw new NotImplementedException();
 	}
 
 	@RequestMapping(value = "/{questionId}/startnewpiround", method = RequestMethod.POST)
@@ -139,9 +140,9 @@ public class ContentController extends PaginationController {
 			) {
 
 		if (time == 0) {
-			contentService.startNewPiRound(questionId, null);
+			timerService.startNewPiRound(questionId, null);
 		} else {
-			contentService.startNewPiRoundDelayed(questionId, time);
+			timerService.startNewPiRoundDelayed(questionId, time);
 		}
 	}
 
@@ -151,7 +152,7 @@ public class ContentController extends PaginationController {
 	public void cancelPiRound(
 			@PathVariable final String questionId
 			) {
-		contentService.cancelPiRoundChange(questionId);
+		timerService.cancelPiRoundChange(questionId);
 	}
 
 	@RequestMapping(value = "/{questionId}/resetpiroundstate", method = RequestMethod.POST)
@@ -160,7 +161,7 @@ public class ContentController extends PaginationController {
 	public void resetPiQuestion(
 			@PathVariable final String questionId
 			) {
-		contentService.resetPiRoundState(questionId);
+		timerService.resetPiRoundState(questionId);
 	}
 
 	@ApiOperation(value = "Set voting admission on question, identified by provided id",
@@ -215,7 +216,7 @@ public class ContentController extends PaginationController {
 			@RequestBody final Content content
 			) {
 		if (publish != null) {
-			content.setActive(publish);
+			content.getState().setVisible(!publish);
 		}
 		contentService.update(content);
 	}
@@ -252,7 +253,7 @@ public class ContentController extends PaginationController {
 			@RequestBody final Content content
 			) {
 		if (showStatistics != null) {
-			content.setShowStatistic(showStatistics);
+			content.getState().setResponsesVisible(showStatistics);
 		}
 		contentService.update(content);
 	}
@@ -266,7 +267,7 @@ public class ContentController extends PaginationController {
 			@RequestBody final Content content
 			) {
 		if (showCorrectAnswer != null) {
-			content.setShowAnswer(showCorrectAnswer);
+			content.getState().setSolutionVisible(showCorrectAnswer);
 		}
 		contentService.update(content);
 	}
@@ -296,8 +297,6 @@ public class ContentController extends PaginationController {
 		if (contents == null || contents.isEmpty()) {
 			response.setStatus(HttpStatus.NO_CONTENT.value());
 			return null;
-		} else if (!requestImageData) {
-			contents = contentService.replaceImageData(contents);
 		}
 
 		return new PaginationListDecorator<>(contents, offset, limit);
@@ -485,7 +484,7 @@ public class ContentController extends PaginationController {
 			final HttpServletResponse response
 			) {
 
-		return contentService.getImage(questionId, answerId);
+		throw new NotImplementedException();
 	}
 
 	@ApiOperation(value = "Delete answer, identified by question ID and answer ID",
diff --git a/src/main/java/de/thm/arsnova/controller/FeedbackController.java b/src/main/java/de/thm/arsnova/controller/FeedbackController.java
index 9f0d32085d050d01916f3072bd0150a0e27092c9..80c94ba002cbc21b072839af078b7bfb7cbd4ff3 100644
--- a/src/main/java/de/thm/arsnova/controller/FeedbackController.java
+++ b/src/main/java/de/thm/arsnova/controller/FeedbackController.java
@@ -22,8 +22,8 @@ import de.thm.arsnova.entities.UserAuthentication;
 import de.thm.arsnova.exceptions.NotFoundException;
 import de.thm.arsnova.services.FeedbackService;
 import de.thm.arsnova.services.UserService;
-import de.thm.arsnova.websocket.ArsnovaSocketioServerImpl;
 import de.thm.arsnova.web.DeprecatedApi;
+import de.thm.arsnova.websocket.ArsnovaSocketioServerImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.web.bind.annotation.PathVariable;
diff --git a/src/main/java/de/thm/arsnova/controller/MotdController.java b/src/main/java/de/thm/arsnova/controller/MotdController.java
index f55be007ac6d182b6d5f2543380c744ed58f5362..b915e5d2074eaebf0827e60696eac45dc42ad5bb 100644
--- a/src/main/java/de/thm/arsnova/controller/MotdController.java
+++ b/src/main/java/de/thm/arsnova/controller/MotdController.java
@@ -17,8 +17,7 @@
  */
 package de.thm.arsnova.controller;
 
-import de.thm.arsnova.entities.migration.v2.Motd;
-import de.thm.arsnova.entities.migration.v2.MotdList;
+import de.thm.arsnova.entities.Motd;
 import de.thm.arsnova.services.MotdService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -46,7 +45,6 @@ import java.util.List;
 @RequestMapping("/motd")
 @Api(value = "/motd", description = "the Motd Controller API")
 public class MotdController extends AbstractController {
-
 	@Autowired
 	private MotdService motdService;
 
@@ -92,8 +90,8 @@ public class MotdController extends AbstractController {
 			) {
 		if (motd != null) {
 			Motd newMotd;
-			if ("session".equals(motd.getAudience()) && motd.getSessionkey() != null) {
-				newMotd = motdService.save(motd.getSessionkey(), motd);
+			if ("session".equals(motd.getAudience()) && motd.getSessionId() != null) {
+				newMotd = motdService.save(motd.getSessionId(), motd);
 			} else {
 				newMotd = motdService.save(motd);
 			}
@@ -109,49 +107,26 @@ public class MotdController extends AbstractController {
 	}
 
 	@ApiOperation(value = "update a message of the day", nickname = "updateMotd")
-	@RequestMapping(value = "/{motdkey}", method = RequestMethod.PUT)
+	@RequestMapping(value = "/{motdId}", method = RequestMethod.PUT)
 	public Motd updateMotd(
-			@ApiParam(value = "motdkey from current motd", required = true) @PathVariable final String motdkey,
+			@ApiParam(value = "motdkey from current motd", required = true) @PathVariable final String motdId,
 			@ApiParam(value = "current motd", required = true) @RequestBody final Motd motd
 			) {
-		if ("session".equals(motd.getAudience()) && motd.getSessionkey() != null) {
-			return motdService.update(motd.getSessionkey(), motd);
+		if ("session".equals(motd.getAudience()) && motd.getSessionId() != null) {
+			return motdService.update(motd.getSessionId(), motd);
 		} else {
 			return motdService.update(motd);
 		}
 	}
 
 	@ApiOperation(value = "deletes a message of the day", nickname = "deleteMotd")
-	@RequestMapping(value = "/{motdkey}", method = RequestMethod.DELETE)
-	public void deleteMotd(@ApiParam(value = "Motd-key from the message that shall be deleted", required = true) @PathVariable final String motdkey) {
-		Motd motd = motdService.getByKey(motdkey);
+	@RequestMapping(value = "/{motdId}", method = RequestMethod.DELETE)
+	public void deleteMotd(@ApiParam(value = "Motd-key from the message that shall be deleted", required = true) @PathVariable final String motdId) {
+		Motd motd = motdService.get(motdId);
 		if ("session".equals(motd.getAudience())) {
-			motdService.deleteBySessionKey(motd.getSessionkey(), motd);
+			motdService.deleteBySessionKey(motd.getSessionId(), motd);
 		} else {
 			motdService.delete(motd);
 		}
 	}
-
-	@ApiOperation(value = "get a list of the motdkeys the current user has confirmed to be read")
-	@RequestMapping(value = "/userlist", method = RequestMethod.GET)
-	public MotdList getUserMotdList(
-			@ApiParam(value = "users name", required = true) @RequestParam(value = "username", defaultValue = "null", required = true) final String username) {
-		return motdService.getMotdListByUsername(username);
-	}
-
-	@ApiOperation(value = "create a list of the motdkeys the current user has confirmed to be read")
-	@RequestMapping(value = "/userlist", method = RequestMethod.POST)
-	public MotdList postUserMotdList(
-			@ApiParam(value = "current motdlist", required = true) @RequestBody final MotdList userMotdList
-			) {
-		return motdService.saveMotdList(userMotdList);
-	}
-
-	@ApiOperation(value = "update a list of the motdkeys the current user has confirmed to be read")
-	@RequestMapping(value = "/userlist", method = RequestMethod.PUT)
-	public MotdList updateUserMotdList(
-			@ApiParam(value = "current motdlist", required = true) @RequestBody final MotdList userMotdList
-			) {
-		return motdService.updateMotdList(userMotdList);
-	}
 }
diff --git a/src/main/java/de/thm/arsnova/controller/SessionController.java b/src/main/java/de/thm/arsnova/controller/SessionController.java
index 8f994479797114e6b23425349c36980545450ce3..889f471aa3c6c395a0966c41c5d1a637c9bd365e 100644
--- a/src/main/java/de/thm/arsnova/controller/SessionController.java
+++ b/src/main/java/de/thm/arsnova/controller/SessionController.java
@@ -18,18 +18,14 @@
 package de.thm.arsnova.controller;
 
 import de.thm.arsnova.connector.model.Course;
-import de.thm.arsnova.entities.migration.v2.Room;
-import de.thm.arsnova.entities.migration.v2.RoomFeature;
-import de.thm.arsnova.entities.migration.v2.RoomInfo;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.transport.ImportExportSession;
 import de.thm.arsnova.entities.transport.ScoreStatistics;
 import de.thm.arsnova.exceptions.UnauthorizedException;
 import de.thm.arsnova.services.RoomService;
-import de.thm.arsnova.services.UserService;
-import de.thm.arsnova.services.RoomServiceImpl.SessionInfoNameComparator;
-import de.thm.arsnova.services.RoomServiceImpl.SessionInfoShortNameComparator;
 import de.thm.arsnova.services.RoomServiceImpl.SessionNameComparator;
 import de.thm.arsnova.services.RoomServiceImpl.SessionShortNameComparator;
+import de.thm.arsnova.services.UserService;
 import de.thm.arsnova.web.DeprecatedApi;
 import de.thm.arsnova.web.Pagination;
 import io.swagger.annotations.Api;
@@ -54,7 +50,7 @@ import java.util.Collections;
 import java.util.List;
 
 /**
- * Handles requests related to ARSnova sessions.
+ * Handles requests related to ARSnova rooms.
  */
 @RestController
 @RequestMapping("/session")
@@ -108,6 +104,7 @@ public class SessionController extends PaginationController {
 	@RequestMapping(value = "/", method = RequestMethod.POST)
 	@ResponseStatus(HttpStatus.CREATED)
 	public Room postNewSession(@ApiParam(value = "current session", required = true) @RequestBody final Room room, final HttpServletResponse response) {
+		/* FIXME: migrate LMS course support
 		if (room != null && room.isCourseSession()) {
 			final List<Course> courses = new ArrayList<>();
 			final Course course = new Course();
@@ -117,18 +114,14 @@ public class SessionController extends PaginationController {
 			if (sessionCount > 0) {
 				final String appendix = " (" + (sessionCount + 1) + ")";
 				room.setName(room.getName() + appendix);
-				room.setShortName(room.getShortName() + appendix);
+				room.setAbbreviation(room.getAbbreviation() + appendix);
 			}
 		}
+		*/
 
-		final Room newSession = roomService.save(room);
-
-		if (newSession == null) {
-			response.setStatus(HttpStatus.SERVICE_UNAVAILABLE.value());
-			return null;
-		}
+		roomService.save(room);
 
-		return newSession;
+		return room;
 	}
 
 	@ApiOperation(value = "updates a session",
@@ -166,14 +159,14 @@ public class SessionController extends PaginationController {
 					"username", defaultValue = "") final String username,
 			final HttpServletResponse response
 			) {
-		List<Room> sessions;
+		List<Room> rooms;
 
 		if (!"".equals(username)) {
 			try {
 				if (ownedOnly && !visitedOnly) {
-					sessions = roomService.getUserSessions(username);
+					rooms = roomService.getUserSessions(username);
 				} else if (visitedOnly && !ownedOnly) {
-					sessions = roomService.getUserVisitedSessions(username);
+					rooms = roomService.getUserVisitedSessions(username);
 				} else {
 					response.setStatus(HttpStatus.NOT_IMPLEMENTED.value());
 					return null;
@@ -185,9 +178,9 @@ public class SessionController extends PaginationController {
 			/* TODO implement all parameter combinations, implement use of user parameter */
 			try {
 				if (ownedOnly && !visitedOnly) {
-					sessions = roomService.getMySessions(offset, limit);
+					rooms = roomService.getMySessions(offset, limit);
 				} else if (visitedOnly && !ownedOnly) {
-					sessions = roomService.getMyVisitedSessions(offset, limit);
+					rooms = roomService.getMyVisitedSessions(offset, limit);
 				} else {
 					response.setStatus(HttpStatus.NOT_IMPLEMENTED.value());
 					return null;
@@ -197,18 +190,18 @@ public class SessionController extends PaginationController {
 			}
 		}
 
-		if (sessions == null || sessions.isEmpty()) {
+		if (rooms == null || rooms.isEmpty()) {
 			response.setStatus(HttpServletResponse.SC_NO_CONTENT);
 			return null;
 		}
 
 		if ("shortname".equals(sortby)) {
-			Collections.sort(sessions, new SessionShortNameComparator());
+			Collections.sort(rooms, new SessionShortNameComparator());
 		} else {
-			Collections.sort(sessions, new SessionNameComparator());
+			Collections.sort(rooms, new SessionNameComparator());
 		}
 
-		return sessions;
+		return rooms;
 	}
 
 	/**
@@ -221,29 +214,29 @@ public class SessionController extends PaginationController {
 	})
 	@RequestMapping(value = "/", method = RequestMethod.GET, params = "statusonly=true")
 	@Pagination
-	public List<RoomInfo> getMySessions(
+	public List<Room> getMySessions(
 			@ApiParam(value = "visitedOnly", required = true) @RequestParam(value = "visitedonly", defaultValue = "false") final boolean visitedOnly,
 			@ApiParam(value = "sort by", required = false) @RequestParam(value = "sortby", defaultValue = "name") final String sortby,
 			final HttpServletResponse response
 			) {
-		List<RoomInfo> sessions;
+		List<Room> rooms;
 		if (!visitedOnly) {
-			sessions = roomService.getMySessionsInfo(offset, limit);
+			rooms = roomService.getMySessionsInfo(offset, limit);
 		} else {
-			sessions = roomService.getMyVisitedSessionsInfo(offset, limit);
+			rooms = roomService.getMyVisitedSessionsInfo(offset, limit);
 		}
 
-		if (sessions == null || sessions.isEmpty()) {
+		if (rooms == null || rooms.isEmpty()) {
 			response.setStatus(HttpServletResponse.SC_NO_CONTENT);
 			return null;
 		}
 
 		if ("shortname".equals(sortby)) {
-			Collections.sort(sessions, new SessionInfoShortNameComparator());
+			Collections.sort(rooms, new SessionShortNameComparator());
 		} else {
-			Collections.sort(sessions, new SessionInfoNameComparator());
+			Collections.sort(rooms, new SessionNameComparator());
 		}
-		return sessions;
+		return rooms;
 	}
 
 	@ApiOperation(value = "Retrieves all public pool sessions for the current user",
@@ -252,10 +245,10 @@ public class SessionController extends PaginationController {
 		@ApiResponse(code = 204, message = HTML_STATUS_204)
 	})
 	@RequestMapping(value = "/publicpool", method = RequestMethod.GET, params = "statusonly=true")
-	public List<RoomInfo> getMyPublicPoolSessions(
+	public List<Room> getMyPublicPoolSessions(
 			final HttpServletResponse response
 			) {
-		List<RoomInfo> sessions = roomService.getMyPublicPoolSessionsInfo();
+		List<Room> sessions = roomService.getMyPublicPoolSessionsInfo();
 
 		if (sessions == null || sessions.isEmpty()) {
 			response.setStatus(HttpServletResponse.SC_NO_CONTENT);
@@ -271,23 +264,23 @@ public class SessionController extends PaginationController {
 		@ApiResponse(code = 204, message = HTML_STATUS_204)
 	})
 	@RequestMapping(value = "/publicpool", method = RequestMethod.GET)
-	public List<RoomInfo> getPublicPoolSessions(
+	public List<Room> getPublicPoolSessions(
 			final HttpServletResponse response
 			) {
-		List<RoomInfo> sessions = roomService.getPublicPoolSessionsInfo();
+		List<Room> rooms = roomService.getPublicPoolSessionsInfo();
 
-		if (sessions == null || sessions.isEmpty()) {
+		if (rooms == null || rooms.isEmpty()) {
 			response.setStatus(HttpServletResponse.SC_NO_CONTENT);
 			return null;
 		}
 
-		return sessions;
+		return rooms;
 	}
 
 	@ApiOperation(value = "imports a session",
 			nickname = "importSession")
 	@RequestMapping(value = "/import", method = RequestMethod.POST)
-	public RoomInfo importSession(
+	public Room importSession(
 			@ApiParam(value = "current session", required = true) @RequestBody final ImportExportSession session,
 			final HttpServletResponse response
 			) {
@@ -317,14 +310,14 @@ public class SessionController extends PaginationController {
 
 	@ApiOperation(value = "copy a session to the public pool if enabled")
 	@RequestMapping(value = "/{sessionkey}/copytopublicpool", method = RequestMethod.POST)
-	public RoomInfo copyToPublicPool(
+	public Room copyToPublicPool(
 			@ApiParam(value = "session-key from current session", required = true) @PathVariable final String sessionkey,
 			@ApiParam(value = "public pool attributes for session", required = true) @RequestBody final de.thm.arsnova.entities.transport.ImportExportSession.PublicPool publicPool
 			) {
 		roomService.setActive(sessionkey, false);
-		RoomInfo sessionInfo = roomService.copySessionToPublicPool(sessionkey, publicPool);
+		Room roomInfo = roomService.copySessionToPublicPool(sessionkey, publicPool);
 		roomService.setActive(sessionkey, true);
-		return sessionInfo;
+		return roomInfo;
 	}
 
 
@@ -373,7 +366,7 @@ public class SessionController extends PaginationController {
 	@ApiOperation(value = "retrieves all session features",
 			nickname = "getSessionFeatures")
 	@RequestMapping(value = "/{sessionkey}/features", method = RequestMethod.GET)
-	public RoomFeature getSessionFeatures(
+	public Room.Settings getSessionFeatures(
 			@ApiParam(value = "session-key from current session", required = true) @PathVariable final String sessionkey,
 			final HttpServletResponse response
 			) {
@@ -383,9 +376,9 @@ public class SessionController extends PaginationController {
 	@RequestMapping(value = "/{sessionkey}/features", method = RequestMethod.PUT)
 	@ApiOperation(value = "change all session features",
 			nickname = "changeSessionFeatures")
-	public RoomFeature changeSessionFeatures(
+	public Room.Settings changeSessionFeatures(
 			@ApiParam(value = "session-key from current session", required = true) @PathVariable final String sessionkey,
-			@ApiParam(value = "session feature", required = true) @RequestBody final RoomFeature features,
+			@ApiParam(value = "session feature", required = true) @RequestBody final Room.Settings features,
 			final HttpServletResponse response
 			) {
 		return roomService.updateFeatures(sessionkey, features);
diff --git a/src/main/java/de/thm/arsnova/controller/SocketController.java b/src/main/java/de/thm/arsnova/controller/SocketController.java
index 82e0f665799381d4df6166fef72af5b8546bea45..3c0bd4922ce9930b61eae60b19f08eddc9f12953 100644
--- a/src/main/java/de/thm/arsnova/controller/SocketController.java
+++ b/src/main/java/de/thm/arsnova/controller/SocketController.java
@@ -18,8 +18,8 @@
 package de.thm.arsnova.controller;
 
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.services.UserService;
 import de.thm.arsnova.services.UserRoomService;
+import de.thm.arsnova.services.UserService;
 import de.thm.arsnova.websocket.ArsnovaSocketioServer;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
diff --git a/src/main/java/de/thm/arsnova/controller/UserController.java b/src/main/java/de/thm/arsnova/controller/UserController.java
index 3d9fd16cc916414ca876a65f95feb915a02244e1..110556b70b09ebe184ae347149e3a83e9318bbe5 100644
--- a/src/main/java/de/thm/arsnova/controller/UserController.java
+++ b/src/main/java/de/thm/arsnova/controller/UserController.java
@@ -17,9 +17,9 @@
  */
 package de.thm.arsnova.controller;
 
-import de.thm.arsnova.entities.migration.v2.DbUser;
-import de.thm.arsnova.services.UserService;
+import de.thm.arsnova.entities.UserProfile;
 import de.thm.arsnova.services.UserRoomService;
+import de.thm.arsnova.services.UserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
 import org.springframework.stereotype.Controller;
@@ -64,10 +64,10 @@ public class UserController extends AbstractController {
 			@PathVariable final String username,
 			@RequestParam final String key, final HttpServletRequest request,
 			final HttpServletResponse response) {
-		DbUser dbUser = userService.getByUsername(username);
-		if (null != dbUser && key.equals(dbUser.getActivationKey())) {
-			dbUser.setActivationKey(null);
-			userService.update(dbUser);
+		UserProfile userProfile = userService.getByUsername(username);
+		if (null != userProfile && key.equals(userProfile.getAccount().getActivationKey())) {
+			userProfile.getAccount().setActivationKey(null);
+			userService.update(userProfile);
 
 			return;
 		}
@@ -92,15 +92,15 @@ public class UserController extends AbstractController {
 			@RequestParam(required = false) final String password,
 			final HttpServletRequest request,
 			final HttpServletResponse response) {
-		DbUser dbUser = userService.getByUsername(username);
-		if (null == dbUser) {
+		UserProfile userProfile = userService.getByUsername(username);
+		if (null == userProfile) {
 			response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 
 			return;
 		}
 
 		if (null != key) {
-			if (!userService.resetPassword(dbUser, key, password)) {
+			if (!userService.resetPassword(userProfile, key, password)) {
 				response.setStatus(HttpServletResponse.SC_FORBIDDEN);
 			}
 		} else {
diff --git a/src/main/java/de/thm/arsnova/entities/ChoiceAnswer.java b/src/main/java/de/thm/arsnova/entities/ChoiceAnswer.java
index 1bb6f31b296e4b22cf950d6852b1c4730818cb3d..242e5e54550d51eedb00130108367196a9251838 100644
--- a/src/main/java/de/thm/arsnova/entities/ChoiceAnswer.java
+++ b/src/main/java/de/thm/arsnova/entities/ChoiceAnswer.java
@@ -1,7 +1,6 @@
 package de.thm.arsnova.entities;
 
 import com.fasterxml.jackson.annotation.JsonView;
-import de.thm.arsnova.entities.migration.v2.AnswerOption;
 import de.thm.arsnova.entities.serialization.View;
 
 import java.util.List;
diff --git a/src/main/java/de/thm/arsnova/entities/migration/ToV2Migrator.java b/src/main/java/de/thm/arsnova/entities/migration/ToV2Migrator.java
index 90924ebba7768092424aa159a8ace9736def1078..892c2e675dc1d651b4ec62efaa75607d8ce979b9 100644
--- a/src/main/java/de/thm/arsnova/entities/migration/ToV2Migrator.java
+++ b/src/main/java/de/thm/arsnova/entities/migration/ToV2Migrator.java
@@ -18,12 +18,12 @@
 package de.thm.arsnova.entities.migration;
 
 import de.thm.arsnova.entities.ChoiceQuestionContent;
-import de.thm.arsnova.entities.migration.v2.Entity;
 import de.thm.arsnova.entities.UserProfile;
 import de.thm.arsnova.entities.migration.v2.Answer;
 import de.thm.arsnova.entities.migration.v2.AnswerOption;
 import de.thm.arsnova.entities.migration.v2.Comment;
 import de.thm.arsnova.entities.migration.v2.Content;
+import de.thm.arsnova.entities.migration.v2.Entity;
 import de.thm.arsnova.entities.migration.v2.LoggedIn;
 import de.thm.arsnova.entities.migration.v2.MotdList;
 import de.thm.arsnova.entities.migration.v2.Room;
diff --git a/src/main/java/de/thm/arsnova/entities/migration/v2/Entity.java b/src/main/java/de/thm/arsnova/entities/migration/v2/Entity.java
index 6eda9e8ba859057312f39a9604f535a68399b190..38528ee379bfe713c3aba13cb0c53e6ad6d0f40e 100644
--- a/src/main/java/de/thm/arsnova/entities/migration/v2/Entity.java
+++ b/src/main/java/de/thm/arsnova/entities/migration/v2/Entity.java
@@ -20,8 +20,6 @@ package de.thm.arsnova.entities.migration.v2;
 import com.fasterxml.jackson.annotation.JsonView;
 import de.thm.arsnova.entities.serialization.View;
 
-import java.util.Date;
-
 public interface Entity {
 	String getId();
 	void setId(String id);
diff --git a/src/main/java/de/thm/arsnova/entities/serialization/CouchDbTypeFieldConverter.java b/src/main/java/de/thm/arsnova/entities/serialization/CouchDbTypeFieldConverter.java
index e261d15a1c4c98f906974816089bf87c2cc55196..3a1cf5225722650706541d807de0a57a3e2e952e 100644
--- a/src/main/java/de/thm/arsnova/entities/serialization/CouchDbTypeFieldConverter.java
+++ b/src/main/java/de/thm/arsnova/entities/serialization/CouchDbTypeFieldConverter.java
@@ -22,11 +22,11 @@ import com.fasterxml.jackson.databind.type.TypeFactory;
 import com.fasterxml.jackson.databind.util.Converter;
 import de.thm.arsnova.entities.migration.v2.Answer;
 import de.thm.arsnova.entities.migration.v2.Comment;
+import de.thm.arsnova.entities.migration.v2.Content;
 import de.thm.arsnova.entities.migration.v2.DbUser;
 import de.thm.arsnova.entities.migration.v2.Entity;
 import de.thm.arsnova.entities.migration.v2.LogEntry;
 import de.thm.arsnova.entities.migration.v2.Motd;
-import de.thm.arsnova.entities.migration.v2.Content;
 import de.thm.arsnova.entities.migration.v2.MotdList;
 import de.thm.arsnova.entities.migration.v2.Room;
 
diff --git a/src/main/java/de/thm/arsnova/entities/transport/AnswerQueueElement.java b/src/main/java/de/thm/arsnova/entities/transport/AnswerQueueElement.java
index 17243c918f0def6c975e140b31d411c25ea24786..672d8c78a010fb4b8b63ea36b969660f0f41d47a 100644
--- a/src/main/java/de/thm/arsnova/entities/transport/AnswerQueueElement.java
+++ b/src/main/java/de/thm/arsnova/entities/transport/AnswerQueueElement.java
@@ -17,10 +17,10 @@
  */
 package de.thm.arsnova.entities.transport;
 
+import de.thm.arsnova.entities.Answer;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Answer;
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
 
 /**
  * An answer that is about to get saved in the database. Answers are not saved immediately, they are instead stored
diff --git a/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java b/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java
index 4f1e8a4bdd9cfdc6f221451039722f884c131512..6798c9e990c3b6a25589b72ff256e87f254a11b2 100644
--- a/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java
+++ b/src/main/java/de/thm/arsnova/entities/transport/ImportExportSession.java
@@ -18,6 +18,7 @@
 package de.thm.arsnova.entities.transport;
 
 import com.fasterxml.jackson.annotation.JsonView;
+import de.thm.arsnova.entities.UserAuthentication;
 import de.thm.arsnova.entities.migration.v2.Answer;
 import de.thm.arsnova.entities.migration.v2.Comment;
 import de.thm.arsnova.entities.migration.v2.Content;
@@ -25,7 +26,6 @@ import de.thm.arsnova.entities.migration.v2.Motd;
 import de.thm.arsnova.entities.migration.v2.Room;
 import de.thm.arsnova.entities.migration.v2.RoomFeature;
 import de.thm.arsnova.entities.migration.v2.RoomInfo;
-import de.thm.arsnova.entities.UserAuthentication;
 import de.thm.arsnova.entities.serialization.View;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
diff --git a/src/main/java/de/thm/arsnova/events/ChangeScoreEvent.java b/src/main/java/de/thm/arsnova/events/ChangeScoreEvent.java
index df76ca4b7ea9313b5cf0283b646d402a8782481f..a69a7622c1723cc406f56d320b724f0dae56e11a 100644
--- a/src/main/java/de/thm/arsnova/events/ChangeScoreEvent.java
+++ b/src/main/java/de/thm/arsnova/events/ChangeScoreEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a score related value changes.
diff --git a/src/main/java/de/thm/arsnova/events/DeleteAllLectureAnswersEvent.java b/src/main/java/de/thm/arsnova/events/DeleteAllLectureAnswersEvent.java
index 4865e7b7df4a5f53010a5152f96919af3337103f..1f75fcf214d539e0005b6db5b4851ee6773ce091 100644
--- a/src/main/java/de/thm/arsnova/events/DeleteAllLectureAnswersEvent.java
+++ b/src/main/java/de/thm/arsnova/events/DeleteAllLectureAnswersEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever all answers of all lecture questions of a session are deleted.
diff --git a/src/main/java/de/thm/arsnova/events/DeleteAllPreparationAnswersEvent.java b/src/main/java/de/thm/arsnova/events/DeleteAllPreparationAnswersEvent.java
index 951e0cf1cc3e4b42dadb6edd2c1d29575e9ba5af..939667318913ff6dca5fb5ba621832ac1d102def 100644
--- a/src/main/java/de/thm/arsnova/events/DeleteAllPreparationAnswersEvent.java
+++ b/src/main/java/de/thm/arsnova/events/DeleteAllPreparationAnswersEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever all answers of all preparation questions of a session are deleted.
diff --git a/src/main/java/de/thm/arsnova/events/DeleteAllQuestionsAnswersEvent.java b/src/main/java/de/thm/arsnova/events/DeleteAllQuestionsAnswersEvent.java
index 78161f0a07d197dadd007083a4dc614c4f4386e6..4aed154481168a39eec7fb480d7408ec7a6ad559 100644
--- a/src/main/java/de/thm/arsnova/events/DeleteAllQuestionsAnswersEvent.java
+++ b/src/main/java/de/thm/arsnova/events/DeleteAllQuestionsAnswersEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever all answers of all questions of a session are deleted.
diff --git a/src/main/java/de/thm/arsnova/events/DeleteAllQuestionsEvent.java b/src/main/java/de/thm/arsnova/events/DeleteAllQuestionsEvent.java
index 82dc2a93976eefd825ab93849a07ee3d7b64aa7e..fe0c7add70426ccd430e8bedbd0fea097d44d697 100644
--- a/src/main/java/de/thm/arsnova/events/DeleteAllQuestionsEvent.java
+++ b/src/main/java/de/thm/arsnova/events/DeleteAllQuestionsEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever all questions of a session are deleted. Note that this implies that all answers are deleted as well,
diff --git a/src/main/java/de/thm/arsnova/events/DeleteAnswerEvent.java b/src/main/java/de/thm/arsnova/events/DeleteAnswerEvent.java
index 99172851eba5bf1363d1f06dbfc66d749d958fa0..f8642545bd324a486e9f2876b6eaff00615f16c1 100644
--- a/src/main/java/de/thm/arsnova/events/DeleteAnswerEvent.java
+++ b/src/main/java/de/thm/arsnova/events/DeleteAnswerEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a single answer is deleted.
diff --git a/src/main/java/de/thm/arsnova/events/DeleteCommentEvent.java b/src/main/java/de/thm/arsnova/events/DeleteCommentEvent.java
index f0a2c378ff15b0711a56d7961153f1896524fda2..5ec64a31a92d96ada045dc3cc2885edd54a2db54 100644
--- a/src/main/java/de/thm/arsnova/events/DeleteCommentEvent.java
+++ b/src/main/java/de/thm/arsnova/events/DeleteCommentEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Comment;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Comment;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever an comment is deleted.
diff --git a/src/main/java/de/thm/arsnova/events/DeleteFeedbackForRoomsEvent.java b/src/main/java/de/thm/arsnova/events/DeleteFeedbackForRoomsEvent.java
index 5446bb178f9371ce9c586f1cd6d37fbf4cd4cf4c..4ddede2787ed7df425390f13f78e9afae7a72bbc 100644
--- a/src/main/java/de/thm/arsnova/events/DeleteFeedbackForRoomsEvent.java
+++ b/src/main/java/de/thm/arsnova/events/DeleteFeedbackForRoomsEvent.java
@@ -18,7 +18,7 @@
 package de.thm.arsnova.events;
 
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 import java.util.Set;
 
diff --git a/src/main/java/de/thm/arsnova/events/DeleteQuestionEvent.java b/src/main/java/de/thm/arsnova/events/DeleteQuestionEvent.java
index 1e8175d22a995971c1f3aa0e0b3fc266ca8a4a82..8f3e5392872148e56c9a562fc05d976c9688d633 100644
--- a/src/main/java/de/thm/arsnova/events/DeleteQuestionEvent.java
+++ b/src/main/java/de/thm/arsnova/events/DeleteQuestionEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a content is deleted.
diff --git a/src/main/java/de/thm/arsnova/events/DeleteRoomEvent.java b/src/main/java/de/thm/arsnova/events/DeleteRoomEvent.java
index 46035570183e2237c93400f9e0f9cc3ffa5d7aa9..c4b6fc2f83ea453f732c38b1bbf21f0296bf1d7e 100644
--- a/src/main/java/de/thm/arsnova/events/DeleteRoomEvent.java
+++ b/src/main/java/de/thm/arsnova/events/DeleteRoomEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a session is deleted. Note that this implies that all related data such as comments,
diff --git a/src/main/java/de/thm/arsnova/events/FeatureChangeEvent.java b/src/main/java/de/thm/arsnova/events/FeatureChangeEvent.java
index c24c1d3e471679153edcb622e329664081de2463..346c06d51c687f39f376771401debfa00a00701c 100644
--- a/src/main/java/de/thm/arsnova/events/FeatureChangeEvent.java
+++ b/src/main/java/de/thm/arsnova/events/FeatureChangeEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a new session is created.
diff --git a/src/main/java/de/thm/arsnova/events/FlipFlashcardsEvent.java b/src/main/java/de/thm/arsnova/events/FlipFlashcardsEvent.java
index ada63c8966ae196c7a87a224a6a5664f60970580..a7484eef5eb626e1846fa7d94707cb67830a1fc6 100644
--- a/src/main/java/de/thm/arsnova/events/FlipFlashcardsEvent.java
+++ b/src/main/java/de/thm/arsnova/events/FlipFlashcardsEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever voting on a question is disabled.
diff --git a/src/main/java/de/thm/arsnova/events/LockFeedbackEvent.java b/src/main/java/de/thm/arsnova/events/LockFeedbackEvent.java
index 80d106a26c386ed5c764101d914ab92f1417a255..2eeadad01055eef46fdca986f24fe26e4c72e430 100644
--- a/src/main/java/de/thm/arsnova/events/LockFeedbackEvent.java
+++ b/src/main/java/de/thm/arsnova/events/LockFeedbackEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever voting on a question is disabled.
diff --git a/src/main/java/de/thm/arsnova/events/LockQuestionEvent.java b/src/main/java/de/thm/arsnova/events/LockQuestionEvent.java
index 72f51f8d322fceaaac2e1ce45fefa9b51c282e06..2949980d272dc2a2184d85151c6bb0418df75442 100644
--- a/src/main/java/de/thm/arsnova/events/LockQuestionEvent.java
+++ b/src/main/java/de/thm/arsnova/events/LockQuestionEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a content is disabled, i.e., it is hidden from students.
diff --git a/src/main/java/de/thm/arsnova/events/LockQuestionsEvent.java b/src/main/java/de/thm/arsnova/events/LockQuestionsEvent.java
index 07d9cb4a26598c842f0e6a7301322ee68dd72d2f..1998da80ef9718547a17dd8f3a2debebc23267f4 100644
--- a/src/main/java/de/thm/arsnova/events/LockQuestionsEvent.java
+++ b/src/main/java/de/thm/arsnova/events/LockQuestionsEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 import java.util.List;
 
diff --git a/src/main/java/de/thm/arsnova/events/LockVoteEvent.java b/src/main/java/de/thm/arsnova/events/LockVoteEvent.java
index c99c9154580721ac897a0f561fd59fc043340a00..0d7e263cef46d5cdbf2716d07e7ce28150f88d22 100644
--- a/src/main/java/de/thm/arsnova/events/LockVoteEvent.java
+++ b/src/main/java/de/thm/arsnova/events/LockVoteEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -41,19 +41,21 @@ public class LockVoteEvent extends RoomEvent {
 		return this.content.getId();
 	}
 
-	public String getQuestionVariant() {
-		return this.content.getQuestionVariant();
+	public String getGroup() {
+		return this.content.getGroup();
 	}
 
 	public Boolean getVotingDisabled() {
-		return this.content.isVotingDisabled();
+		/* FIXME: migrate */
+		return false;
+		//return this.content.isVotingDisabled();
 	}
 
 	public Map<String, Object> getVotingAdmission() {
 		Map<String, Object> map = new HashMap<>();
 
 		map.put("_id", getQuestionId());
-		map.put("variant", getQuestionVariant());
+		map.put("variant", getGroup());
 		return map;
 	}
 
diff --git a/src/main/java/de/thm/arsnova/events/LockVotesEvent.java b/src/main/java/de/thm/arsnova/events/LockVotesEvent.java
index d90f6c366b7c6cd7c5f86e31dd60a03b0aa0d988..2339b8593914c1f35def81f8e8b4241e10641116 100644
--- a/src/main/java/de/thm/arsnova/events/LockVotesEvent.java
+++ b/src/main/java/de/thm/arsnova/events/LockVotesEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 import java.util.List;
 
diff --git a/src/main/java/de/thm/arsnova/events/NewAnswerEvent.java b/src/main/java/de/thm/arsnova/events/NewAnswerEvent.java
index 9b3139ad6ab43624667251357f93582555fa87e1..8122320b4c8185c1614e922cf305d7008b839c3e 100644
--- a/src/main/java/de/thm/arsnova/events/NewAnswerEvent.java
+++ b/src/main/java/de/thm/arsnova/events/NewAnswerEvent.java
@@ -18,9 +18,9 @@
 package de.thm.arsnova.events;
 
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Answer;
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Answer;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a new answer is added.
diff --git a/src/main/java/de/thm/arsnova/events/NewCommentEvent.java b/src/main/java/de/thm/arsnova/events/NewCommentEvent.java
index 126e4f10621bd993d1c0b8cf8a4f9dcbc00ebe08..df5b09baa0e5520e950077657d118658d3e0d918 100644
--- a/src/main/java/de/thm/arsnova/events/NewCommentEvent.java
+++ b/src/main/java/de/thm/arsnova/events/NewCommentEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Comment;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Comment;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a new comment is added.
diff --git a/src/main/java/de/thm/arsnova/events/NewFeedbackEvent.java b/src/main/java/de/thm/arsnova/events/NewFeedbackEvent.java
index fe8862534eb59aa2983d0539608d9917443060b0..cdee0f7eba02625e1dde79fff51273f0363b34dd 100644
--- a/src/main/java/de/thm/arsnova/events/NewFeedbackEvent.java
+++ b/src/main/java/de/thm/arsnova/events/NewFeedbackEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever the feedback changes.
diff --git a/src/main/java/de/thm/arsnova/events/NewQuestionEvent.java b/src/main/java/de/thm/arsnova/events/NewQuestionEvent.java
index a5b14842be84a85e146da46986b347134fa7774a..cf49229b4d8934a7c506828cd796decfa0625e98 100644
--- a/src/main/java/de/thm/arsnova/events/NewQuestionEvent.java
+++ b/src/main/java/de/thm/arsnova/events/NewQuestionEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a new content is added.
diff --git a/src/main/java/de/thm/arsnova/events/NewRoomEvent.java b/src/main/java/de/thm/arsnova/events/NewRoomEvent.java
index 601fefb4f648f9bcd223aa40405c96a197b8fcb0..391c5f5c8319715413e1bf9cc11399436f8c5a86 100644
--- a/src/main/java/de/thm/arsnova/events/NewRoomEvent.java
+++ b/src/main/java/de/thm/arsnova/events/NewRoomEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a new session is created.
diff --git a/src/main/java/de/thm/arsnova/events/PiRoundCancelEvent.java b/src/main/java/de/thm/arsnova/events/PiRoundCancelEvent.java
index 517b5ce3367e1b2b81a7fc4d8826c7a6cf4265dc..77e41392fea59e4ff19d0990c101195d352c6b9a 100644
--- a/src/main/java/de/thm/arsnova/events/PiRoundCancelEvent.java
+++ b/src/main/java/de/thm/arsnova/events/PiRoundCancelEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a peer instruction round is canceled.
diff --git a/src/main/java/de/thm/arsnova/events/PiRoundDelayedStartEvent.java b/src/main/java/de/thm/arsnova/events/PiRoundDelayedStartEvent.java
index 1e2430e54fb5e8a52d90bf108b8a7b9bfed0dbc6..510bbf7a9abf932c00a8ef67d3a8ec9eea0062c7 100644
--- a/src/main/java/de/thm/arsnova/events/PiRoundDelayedStartEvent.java
+++ b/src/main/java/de/thm/arsnova/events/PiRoundDelayedStartEvent.java
@@ -17,9 +17,10 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -31,18 +32,18 @@ public class PiRoundDelayedStartEvent extends RoomEvent {
 
 	private static final long serialVersionUID = 1L;
 	private final String questionId;
-	private final Long startTime;
-	private final Long endTime;
-	private final String questionVariant;
+	private final Date startTime;
+	private final Date endTime;
+	private final String group;
 	private int piRound;
 
 	public PiRoundDelayedStartEvent(Object source, Room room, Content content) {
 		super(source, room);
 		this.questionId = content.getId();
-		this.startTime = content.getPiRoundStartTime();
-		this.endTime = content.getPiRoundEndTime();
-		this.questionVariant = content.getQuestionVariant();
-		this.piRound = content.getPiRound();
+		this.group = content.getGroup();
+		this.piRound = content.getState().getRound();
+		this.endTime = content.getState().getRoundEndTimestamp();
+		this.startTime = new Date();
 	}
 
 	@Override
@@ -54,16 +55,16 @@ public class PiRoundDelayedStartEvent extends RoomEvent {
 		return questionId;
 	}
 
-	public Long getStartTime() {
+	public Date getStartTime() {
 		return startTime;
 	}
 
-	public Long getEndTime() {
+	public Date getEndTime() {
 		return endTime;
 	}
 
-	public String getQuestionVariant() {
-		return questionVariant;
+	public String getGroup() {
+		return group;
 	}
 
 	public Integer getPiRound() {
@@ -74,9 +75,9 @@ public class PiRoundDelayedStartEvent extends RoomEvent {
 		Map<String, Object> map = new HashMap<>();
 
 		map.put("_id", getQuestionId());
-		map.put("endTime", getEndTime());
-		map.put("startTime", getStartTime());
-		map.put("variant", getQuestionVariant());
+		map.put("endTime", getEndTime().getTime());
+		map.put("startTime", getStartTime().getTime());
+		map.put("variant", getGroup());
 		map.put("round", getPiRound());
 
 		return map;
diff --git a/src/main/java/de/thm/arsnova/events/PiRoundEndEvent.java b/src/main/java/de/thm/arsnova/events/PiRoundEndEvent.java
index 471f3b73d383cf8c16c028a6b3080cbb2b571513..188be7b494e280abd76e5bfb0c3fbdbba96e0414 100644
--- a/src/main/java/de/thm/arsnova/events/PiRoundEndEvent.java
+++ b/src/main/java/de/thm/arsnova/events/PiRoundEndEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -30,13 +30,13 @@ public class PiRoundEndEvent extends RoomEvent {
 
 	private static final long serialVersionUID = 1L;
 
-	private final String questionId;
-	private final String questionVariant;
+	private final String contentId;
+	private final String group;
 
 	public PiRoundEndEvent(Object source, Room room, Content content) {
 		super(source, room);
-		questionId = content.getId();
-		questionVariant = content.getQuestionVariant();
+		contentId = content.getId();
+		group = content.getGroup();
 	}
 
 	@Override
@@ -44,19 +44,19 @@ public class PiRoundEndEvent extends RoomEvent {
 		visitor.visit(this);
 	}
 
-	public String getQuestionId() {
-		return questionId;
+	public String getContentId() {
+		return contentId;
 	}
 
-	public String getQuestionVariant() {
-		return questionVariant;
+	public String getGroup() {
+		return group;
 	}
 
 	public Map<String, String> getPiRoundEndInformations() {
 		Map<String, String> map = new HashMap<>();
 
-		map.put("_id", getQuestionId());
-		map.put("variant", getQuestionVariant());
+		map.put("_id", getContentId());
+		map.put("variant", getGroup());
 
 		return map;
 	}
diff --git a/src/main/java/de/thm/arsnova/events/PiRoundResetEvent.java b/src/main/java/de/thm/arsnova/events/PiRoundResetEvent.java
index 293dd31b977039be864feb0097a6e27452b06d0e..52958abd277dbafe53baec95993c173eae5618af 100644
--- a/src/main/java/de/thm/arsnova/events/PiRoundResetEvent.java
+++ b/src/main/java/de/thm/arsnova/events/PiRoundResetEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -30,13 +30,13 @@ public class PiRoundResetEvent extends RoomEvent {
 
 	private static final long serialVersionUID = 1L;
 
-	private final String questionId;
-	private final String questionVariant;
+	private final String contentId;
+	private final String group;
 
 	public PiRoundResetEvent(Object source, Room room, Content content) {
 		super(source, room);
-		questionId = content.getId();
-		questionVariant = content.getQuestionVariant();
+		contentId = content.getId();
+		group = content.getGroup();
 	}
 
 	@Override
@@ -44,19 +44,19 @@ public class PiRoundResetEvent extends RoomEvent {
 		visitor.visit(this);
 	}
 
-	public String getQuestionId() {
-		return questionId;
+	public String getContentId() {
+		return contentId;
 	}
 
-	public String getQuestionVariant() {
-		return questionVariant;
+	public String getGroup() {
+		return group;
 	}
 
 	public Map<String, String> getPiRoundResetInformations() {
 		Map<String, String> map = new HashMap<>();
 
-		map.put("_id", getQuestionId());
-		map.put("variant", getQuestionVariant());
+		map.put("_id", getContentId());
+		map.put("variant", getGroup());
 
 		return map;
 	}
diff --git a/src/main/java/de/thm/arsnova/events/RoomEvent.java b/src/main/java/de/thm/arsnova/events/RoomEvent.java
index a4fb5cdcb6f245f3eadd2020bd54ae33b5776ff9..421ce253495a7bbf2fc95ad55f3059b25ace381d 100644
--- a/src/main/java/de/thm/arsnova/events/RoomEvent.java
+++ b/src/main/java/de/thm/arsnova/events/RoomEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Base class for all {@link ArsnovaEvent}s that are related to a room.
diff --git a/src/main/java/de/thm/arsnova/events/StatusRoomEvent.java b/src/main/java/de/thm/arsnova/events/StatusRoomEvent.java
index 6d4307db0aeb2dda897e2b8a32cd3b6c3ed33886..ad2b4d1a2958bdc36239f8a288ddde93c47a926f 100644
--- a/src/main/java/de/thm/arsnova/events/StatusRoomEvent.java
+++ b/src/main/java/de/thm/arsnova/events/StatusRoomEvent.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever the status of a session changes, i.e., it is enabled or disabled.
diff --git a/src/main/java/de/thm/arsnova/events/UnlockQuestionEvent.java b/src/main/java/de/thm/arsnova/events/UnlockQuestionEvent.java
index 5a92add979ff1bc39db385698d556ea16697cd8a..6d23f81eb0ba78854022c5b1eca48e8f80d0f9a8 100644
--- a/src/main/java/de/thm/arsnova/events/UnlockQuestionEvent.java
+++ b/src/main/java/de/thm/arsnova/events/UnlockQuestionEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 /**
  * Fires whenever a content is enabled, i.e., it becomes visible to students.
diff --git a/src/main/java/de/thm/arsnova/events/UnlockQuestionsEvent.java b/src/main/java/de/thm/arsnova/events/UnlockQuestionsEvent.java
index 76614913f75d47c5ad17fe69d8a8df25a50412fa..be6dd5dd42521d2dae45f64cabd6f666037aa02a 100644
--- a/src/main/java/de/thm/arsnova/events/UnlockQuestionsEvent.java
+++ b/src/main/java/de/thm/arsnova/events/UnlockQuestionsEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 import java.util.List;
 
diff --git a/src/main/java/de/thm/arsnova/events/UnlockVoteEvent.java b/src/main/java/de/thm/arsnova/events/UnlockVoteEvent.java
index f824b19015a58cdaf568784ba73c1cb25effb1ab..eaf286f8851e5bb83f8ba545692c63535b9e20ec 100644
--- a/src/main/java/de/thm/arsnova/events/UnlockVoteEvent.java
+++ b/src/main/java/de/thm/arsnova/events/UnlockVoteEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -41,19 +41,19 @@ public class UnlockVoteEvent extends RoomEvent {
 		return this.content.getId();
 	}
 
-	public String getQuestionVariant() {
-		return this.content.getQuestionVariant();
+	public String getGroup() {
+		return this.content.getGroup();
 	}
 
 	public Boolean getVotingDisabled() {
-		return this.content.isVotingDisabled();
+		return !this.content.getState().areResponsesEnabled();
 	}
 
 	public Map<String, Object> getVotingAdmission() {
 		Map<String, Object> map = new HashMap<>();
 
 		map.put("_id", getQuestionId());
-		map.put("variant", getQuestionVariant());
+		map.put("variant", getGroup());
 		return map;
 	}
 
diff --git a/src/main/java/de/thm/arsnova/events/UnlockVotesEvent.java b/src/main/java/de/thm/arsnova/events/UnlockVotesEvent.java
index 7f907cdb0783acb292e0d264f7f5d1bfd6f24ef0..8c49926c89628eab1dad2cf24dd6218d45c31612 100644
--- a/src/main/java/de/thm/arsnova/events/UnlockVotesEvent.java
+++ b/src/main/java/de/thm/arsnova/events/UnlockVotesEvent.java
@@ -17,8 +17,8 @@
  */
 package de.thm.arsnova.events;
 
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
 
 import java.util.List;
 
diff --git a/src/main/java/de/thm/arsnova/persistance/AnswerRepository.java b/src/main/java/de/thm/arsnova/persistance/AnswerRepository.java
index d59eb8b1ef7ffe5bf6cca0126ef57ea73348b687..1f658bd92e32e6aea4b47d98cb5abcdebbd1573e 100644
--- a/src/main/java/de/thm/arsnova/persistance/AnswerRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/AnswerRepository.java
@@ -17,16 +17,16 @@
  */
 package de.thm.arsnova.persistance;
 
+import de.thm.arsnova.entities.Answer;
+import de.thm.arsnova.entities.AnswerStatistics;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Answer;
 import org.springframework.data.repository.CrudRepository;
 
 import java.util.List;
 
 public interface AnswerRepository extends CrudRepository<Answer, String> {
 	Answer findByQuestionIdUserPiRound(String questionId, UserAuthentication user, int piRound);
-	List<Answer> findByContentIdPiRound(String contentId, int piRound);
-	List<Answer> findByContentId(String contentId);
+	AnswerStatistics findByContentIdPiRound(String contentId, int piRound);
 	int countByContentIdRound(String contentId, int round);
 	int countByContentId(String contentId);
 	List<Answer> findByContentId(String contentId, int start, int limit);
diff --git a/src/main/java/de/thm/arsnova/persistance/CommentRepository.java b/src/main/java/de/thm/arsnova/persistance/CommentRepository.java
index 228f50d3b9a4bb67d3941738e63ad1dddac25bb1..dea65095f38db593ce81220283edcca60ccf9d0e 100644
--- a/src/main/java/de/thm/arsnova/persistance/CommentRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/CommentRepository.java
@@ -1,7 +1,7 @@
 package de.thm.arsnova.persistance;
 
+import de.thm.arsnova.entities.Comment;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Comment;
 import de.thm.arsnova.entities.migration.v2.CommentReadingCount;
 import org.springframework.data.repository.CrudRepository;
 
diff --git a/src/main/java/de/thm/arsnova/persistance/ContentRepository.java b/src/main/java/de/thm/arsnova/persistance/ContentRepository.java
index e4363c34bd76ae1dcb08110946ed18ebc04a141e..3212b43c1fed6529e632f6e4457b26f57b6eccf8 100644
--- a/src/main/java/de/thm/arsnova/persistance/ContentRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/ContentRepository.java
@@ -1,6 +1,6 @@
 package de.thm.arsnova.persistance;
 
-import de.thm.arsnova.entities.migration.v2.Content;
+import de.thm.arsnova.entities.Content;
 import de.thm.arsnova.entities.UserAuthentication;
 import org.springframework.data.repository.CrudRepository;
 
diff --git a/src/main/java/de/thm/arsnova/persistance/MotdRepository.java b/src/main/java/de/thm/arsnova/persistance/MotdRepository.java
index e8c8a752e75977fdfe68920a48bbd016917abbb1..f403ccb271ee40c73f8685f4ee7551c097bc571e 100644
--- a/src/main/java/de/thm/arsnova/persistance/MotdRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/MotdRepository.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.persistance;
 
-import de.thm.arsnova.entities.migration.v2.Motd;
+import de.thm.arsnova.entities.Motd;
 import org.springframework.data.repository.CrudRepository;
 
 import java.util.List;
diff --git a/src/main/java/de/thm/arsnova/persistance/RoomRepository.java b/src/main/java/de/thm/arsnova/persistance/RoomRepository.java
index 07cfe6ec6228f4469eabfbfdf6a3f800947db226..b9e577ab332a9a235bb09188cba41a0bceba78d7 100644
--- a/src/main/java/de/thm/arsnova/persistance/RoomRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/RoomRepository.java
@@ -18,10 +18,9 @@
 package de.thm.arsnova.persistance;
 
 import de.thm.arsnova.connector.model.Course;
-import de.thm.arsnova.entities.migration.v2.LoggedIn;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Room;
-import de.thm.arsnova.entities.migration.v2.RoomInfo;
+import de.thm.arsnova.entities.migration.v2.LoggedIn;
 import de.thm.arsnova.entities.transport.ImportExportSession;
 import org.springframework.data.repository.CrudRepository;
 
@@ -34,13 +33,12 @@ public interface RoomRepository extends CrudRepository<Room, String> {
 	List<Room> findByUsername(String username, int start, int limit);
 	List<Room> findAllForPublicPool();
 	List<Room> findForPublicPoolByUser(UserAuthentication user);
-	List<Room> findVisitedByUsername(String username, int start, int limit);
-	List<RoomInfo> getMySessionsInfo(UserAuthentication user, int start, int limit);
-	List<RoomInfo> findInfosForPublicPool();
-	List<RoomInfo> findInfosForPublicPoolByUser(UserAuthentication user);
-	List<RoomInfo> findInfoForVisitedByUser(UserAuthentication currentUser, int start, int limit);
+	List<Room> getRoomsWithStatsForUser(UserAuthentication user, int start, int limit);
+	List<Room> getVisitedRoomsWithStatsForUser(List<Room> rooms, UserAuthentication user);
+	List<Room> findInfosForPublicPool();
+	List<Room> findInfosForPublicPoolByUser(UserAuthentication user);
 	List<Room> findSessionsByCourses(List<Course> courses);
-	RoomInfo importSession(UserAuthentication user, ImportExportSession importSession);
+	Room importSession(UserAuthentication user, ImportExportSession importSession);
 	ImportExportSession exportSession(String sessionkey, Boolean withAnswer, Boolean withFeedbackQuestions);
 	LoggedIn registerAsOnlineUser(UserAuthentication user, Room room);
 }
diff --git a/src/main/java/de/thm/arsnova/persistance/SessionStatisticsRepository.java b/src/main/java/de/thm/arsnova/persistance/SessionStatisticsRepository.java
index cc0b890a780db769112c4adb137471e6a9249ca7..8396dbedde24ebeca6165e479cc6becd52b1035d 100644
--- a/src/main/java/de/thm/arsnova/persistance/SessionStatisticsRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/SessionStatisticsRepository.java
@@ -1,6 +1,6 @@
 package de.thm.arsnova.persistance;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.services.score.Score;
 
 public interface SessionStatisticsRepository {
diff --git a/src/main/java/de/thm/arsnova/persistance/UserRepository.java b/src/main/java/de/thm/arsnova/persistance/UserRepository.java
index 0f6334254c594f18398336928a250a0efc9faf79..4540a976d9f2761228e944215090ca5ac1f4612c 100644
--- a/src/main/java/de/thm/arsnova/persistance/UserRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/UserRepository.java
@@ -17,10 +17,10 @@
  */
 package de.thm.arsnova.persistance;
 
-import de.thm.arsnova.entities.migration.v2.DbUser;
+import de.thm.arsnova.entities.UserProfile;
 import org.springframework.data.repository.CrudRepository;
 
-public interface UserRepository extends CrudRepository<DbUser, String> {
-	DbUser findByUsername(String username);
+public interface UserRepository extends CrudRepository<UserProfile, String> {
+	UserProfile findByUsername(String username);
 	int deleteInactiveUsers(long lastActivityBefore);
 }
diff --git a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbAnswerRepository.java b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbAnswerRepository.java
index d63f4c066ac4aa6f891db16eb5b211d3ab190ab5..95a14a1f28ee21409a881c7889f94e45a65f92cd 100644
--- a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbAnswerRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbAnswerRepository.java
@@ -1,9 +1,9 @@
 package de.thm.arsnova.persistance.couchdb;
 
-import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.Lists;
+import de.thm.arsnova.entities.Answer;
+import de.thm.arsnova.entities.AnswerStatistics;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Answer;
 import de.thm.arsnova.persistance.AnswerRepository;
 import de.thm.arsnova.persistance.LogEntryRepository;
 import org.ektorp.BulkDeleteDocument;
@@ -77,53 +77,34 @@ public class CouchDbAnswerRepository extends CouchDbCrudRepository<Answer> imple
 	}
 
 	@Override
-	public List<Answer> findByContentIdPiRound(final String contentId, final int piRound) {
-		final String questionId = contentId;
+	public AnswerStatistics findByContentIdPiRound(final String contentId, final int piRound) {
 		final ViewResult result = db.queryView(createQuery("by_questionid_piround_text_subject")
 						.group(true)
-						.startKey(ComplexKey.of(questionId, piRound))
-						.endKey(ComplexKey.of(questionId, piRound, ComplexKey.emptyObject())));
-		final int abstentionCount = countByContentId(questionId);
-
-		final List<Answer> answers = new ArrayList<>();
-		for (final ViewResult.Row d : result) {
-			final Answer a = new Answer();
-			a.setAnswerCount(d.getValueAsInt());
-			a.setAbstentionCount(abstentionCount);
-			a.setQuestionId(d.getKeyAsNode().get(0).asText());
-			a.setPiRound(piRound);
-			final JsonNode answerTextNode = d.getKeyAsNode().get(3);
-			a.setAnswerText(answerTextNode.isNull() ? null : answerTextNode.asText());
-			answers.add(a);
-		}
-
-		return answers;
-	}
-
-	@Override
-	public List<Answer> findByContentId(final String contentId) {
-		final ViewResult result = db.queryView(createQuery("by_questionid_piround_text_subject")
-				.group(true)
-				.startKey(ComplexKey.of(contentId))
-				.endKey(ComplexKey.of(contentId, ComplexKey.emptyObject())));
+						.startKey(ComplexKey.of(contentId, piRound))
+						.endKey(ComplexKey.of(contentId, piRound, ComplexKey.emptyObject())));
 		final int abstentionCount = countByContentId(contentId);
 
-		final List<Answer> answers = new ArrayList<>();
-		for (final ViewResult.Row d : result.getRows()) {
-			final Answer a = new Answer();
-			a.setAnswerCount(d.getValueAsInt());
-			a.setAbstentionCount(abstentionCount);
-			a.setQuestionId(d.getKeyAsNode().get(0).asText());
-			final JsonNode answerTextNode = d.getKeyAsNode().get(3);
-			final JsonNode answerSubjectNode = d.getKeyAsNode().get(4);
-			final boolean successfulFreeTextAnswer = d.getKeyAsNode().get(5).asBoolean();
-			a.setAnswerText(answerTextNode.isNull() ? null : answerTextNode.asText());
-			a.setAnswerSubject(answerSubjectNode.isNull() ? null : answerSubjectNode.asText());
-			a.setSuccessfulFreeTextAnswer(successfulFreeTextAnswer);
-			answers.add(a);
+		final AnswerStatistics stats = new AnswerStatistics();
+		stats.setContentId(contentId);
+		final AnswerStatistics.RoundStatistics roundStats = stats.new RoundStatistics();
+		roundStats.setRound(piRound);
+		roundStats.setAbstentionCount(abstentionCount);
+		/* FIXME: determine correct array size dynamically */
+		final int[] independentCounts = new int[16];
+		for (final ViewResult.Row d : result) {
+			if (d.getKeyAsNode().get(3).asBoolean()) {
+				roundStats.setAbstentionCount(d.getValueAsInt());
+			} else {
+				int optionIndex = d.getKeyAsNode().get(4).asInt();
+				independentCounts[optionIndex] = d.getValueAsInt();
+			}
 		}
+		roundStats.setIndependentCounts(independentCounts);
+		List<AnswerStatistics.RoundStatistics> roundStatisticsList = new ArrayList<>();
+		roundStatisticsList.add(roundStats);
+		stats.setRoundStatistics(roundStatisticsList);
 
-		return answers;
+		return stats;
 	}
 
 	@Override
diff --git a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbCommentRepository.java b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbCommentRepository.java
index bf2ba838b076dc174e2a0004e66eebf201169f39..7541a3379aabc3013c2633c7beee0ccb470c873f 100644
--- a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbCommentRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbCommentRepository.java
@@ -1,8 +1,8 @@
 package de.thm.arsnova.persistance.couchdb;
 
 import com.fasterxml.jackson.databind.JsonNode;
+import de.thm.arsnova.entities.Comment;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Comment;
 import de.thm.arsnova.entities.migration.v2.CommentReadingCount;
 import de.thm.arsnova.persistance.CommentRepository;
 import de.thm.arsnova.persistance.LogEntryRepository;
diff --git a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbContentRepository.java b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbContentRepository.java
index 119a6b05c3e5c512c1ad839cec894c85b9011ed3..a53e47eda868b9bce169c7b97a125745f1eaae78 100644
--- a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbContentRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbContentRepository.java
@@ -1,7 +1,7 @@
 package de.thm.arsnova.persistance.couchdb;
 
+import de.thm.arsnova.entities.Content;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Content;
 import de.thm.arsnova.persistance.ContentRepository;
 import de.thm.arsnova.persistance.LogEntryRepository;
 import org.ektorp.BulkDeleteDocument;
@@ -167,18 +167,13 @@ public class CouchDbContentRepository extends CouchDbCrudRepository<Content> imp
 	public List<Content> findBySessionIdAndVariantAndActive(final Object... keys) {
 		final Object[] endKeys = Arrays.copyOf(keys, keys.length + 1);
 		endKeys[keys.length] = ComplexKey.emptyObject();
-		final List<Content> contents = db.queryView(createQuery("by_sessionid_variant_active")
+
+		return db.queryView(createQuery("by_sessionid_variant_active")
 						.includeDocs(true)
 						.reduce(false)
 						.startKey(ComplexKey.of(keys))
 						.endKey(ComplexKey.of(endKeys)),
 				Content.class);
-		for (final Content content : contents) {
-			content.updateRoundManagementState();
-			//content.setSessionKeyword(session.getKeyword());
-		}
-
-		return contents;
 	}
 
 	@Override
@@ -231,8 +226,8 @@ public class CouchDbContentRepository extends CouchDbCrudRepository<Content> imp
 		final List<String> unanswered = new ArrayList<>();
 
 		for (final Content content : contents) {
-			if (!"slide".equals(content.getQuestionType()) && (!answeredQuestions.containsKey(content.getId())
-					|| (answeredQuestions.containsKey(content.getId()) && answeredQuestions.get(content.getId()) != content.getPiRound()))) {
+			if (!"slide".equals(content.getFormat()) && (!answeredQuestions.containsKey(content.getId())
+					|| (answeredQuestions.containsKey(content.getId()) && answeredQuestions.get(content.getId()) != content.getState().getRound()))) {
 				unanswered.add(content.getId());
 			}
 		}
diff --git a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbMotdRepository.java b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbMotdRepository.java
index e0e2650afc7c9a10be5e3aab795864a9bd4af27d..d7c5317b9d981df8dbcae5a6684cdfe504fd9979 100644
--- a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbMotdRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbMotdRepository.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.persistance.couchdb;
 
-import de.thm.arsnova.entities.migration.v2.Motd;
+import de.thm.arsnova.entities.Motd;
 import de.thm.arsnova.persistance.MotdRepository;
 import org.ektorp.CouchDbConnector;
 import org.slf4j.Logger;
diff --git a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbRoomRepository.java b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbRoomRepository.java
index 1538ae8939a016f2eb53bd926938ca50d6676d66..0a3a18a10df6adab658f5ece430edea2206bc011 100644
--- a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbRoomRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbRoomRepository.java
@@ -18,20 +18,16 @@
 package de.thm.arsnova.persistance.couchdb;
 
 import de.thm.arsnova.connector.model.Course;
+import de.thm.arsnova.entities.Room;
+import de.thm.arsnova.entities.RoomStatistics;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Comment;
 import de.thm.arsnova.entities.migration.v2.LoggedIn;
-import de.thm.arsnova.entities.migration.v2.Room;
-import de.thm.arsnova.entities.migration.v2.RoomInfo;
-import de.thm.arsnova.entities.migration.v2.VisitedRoom;
 import de.thm.arsnova.entities.transport.ImportExportSession;
-import de.thm.arsnova.exceptions.NotFoundException;
 import de.thm.arsnova.persistance.LogEntryRepository;
 import de.thm.arsnova.persistance.MotdRepository;
 import de.thm.arsnova.persistance.RoomRepository;
 import org.ektorp.ComplexKey;
 import org.ektorp.CouchDbConnector;
-import org.ektorp.DocumentNotFoundException;
 import org.ektorp.UpdateConflictException;
 import org.ektorp.ViewQuery;
 import org.ektorp.ViewResult;
@@ -80,76 +76,7 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 			return null;
 		}
 
-		return room.getKeyword();
-	}
-
-	@Override
-	public List<Room> findVisitedByUsername(final String username, final int start, final int limit) {
-		final int qSkip = start > 0 ? start : -1;
-		final int qLimit = limit > 0 ? limit : -1;
-
-		try {
-			final ViewResult visitedSessionResult = db.queryView(createQuery("visited_sessions_by_user")
-					.designDocId("_design/LoggedIn").key(username));
-			final List<Room> visitedSessions = visitedSessionResult.getRows().stream().map(vs -> {
-				final Room s = new Room();
-				s.setId(vs.getValueAsNode().get("_id").asText());
-				s.setKeyword(vs.getValueAsNode().get("keyword").asText());
-				s.setName(vs.getValueAsNode().get("name").asText());
-
-				return s;
-			}).collect(Collectors.toList());
-
-			if (visitedSessions.isEmpty()) {
-				return new ArrayList<>();
-			}
-
-			// Filter sessions that don't exist anymore, also filter my own sessions
-			final List<Room> result = new ArrayList<>();
-			final List<Room> filteredSessions = new ArrayList<>();
-			for (final Room s : visitedSessions) {
-				try {
-					/* FIXME: caching (getSessionFromKeyword) */
-					final Room room = findByKeyword(s.getKeyword());
-					if (room != null && !(room.getCreator().equals(username))) {
-						result.add(room);
-					} else {
-						filteredSessions.add(s);
-					}
-				} catch (final NotFoundException e) {
-					filteredSessions.add(s);
-				}
-			}
-			if (filteredSessions.isEmpty()) {
-				return result;
-			}
-			// Update document to remove sessions that don't exist anymore
-			final List<VisitedRoom> newVisitedSessions = new ArrayList<>();
-			for (final Room s : result) {
-				newVisitedSessions.add(new VisitedRoom(s));
-			}
-
-			try {
-				final LoggedIn loggedIn = db.get(LoggedIn.class, visitedSessionResult.getRows().get(0).getId());
-				loggedIn.setVisitedSessions(newVisitedSessions);
-				db.update(loggedIn);
-			} catch (UpdateConflictException e) {
-				logger.error("Could not clean up LoggedIn document of {}.", username, e);
-			}
-
-			return result;
-		} catch (final DocumentNotFoundException e) {
-			return new ArrayList<>();
-		}
-	}
-
-	@Override
-	public List<RoomInfo> findInfoForVisitedByUser(final UserAuthentication user, final int start, final int limit) {
-		final List<Room> sessions = findVisitedByUsername(user.getUsername(), start, limit);
-		if (sessions.isEmpty()) {
-			return new ArrayList<>();
-		}
-		return this.getInfosForVisitedSessions(sessions, user);
+		return room.getShortId();
 	}
 
 	@Override
@@ -177,7 +104,7 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 
 	/* TODO: Move to service layer. */
 	@Override
-	public RoomInfo importSession(final UserAuthentication user, final ImportExportSession importSession) {
+	public Room importSession(final UserAuthentication user, final ImportExportSession importSession) {
 		/* FIXME: not yet migrated - move to service layer */
 		throw new UnsupportedOperationException();
 //		final Room session = this.saveSession(user, importSession.generateSessionEntity(user));
@@ -213,9 +140,9 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 //					final Document answerDoc = new Document();
 //					answerDoc.put("type", "skill_question_answer");
 //					answerDoc.put("sessionId", a.getRoomId());
-//					answerDoc.put("questionId", a.getQuestionId());
+//					answerDoc.put("questionId", a.getContentId());
 //					answerDoc.put("answerSubject", a.getAnswerSubject());
-//					answerDoc.put("questionVariant", a.getQuestionVariant());
+//					answerDoc.put("questionVariant", a.getGroup());
 //					answerDoc.put("questionValue", a.getQuestionValue());
 //					answerDoc.put("answerText", a.getAnswerText());
 //					answerDoc.put("answerTextRaw", a.getAnswerTextRaw());
@@ -313,28 +240,31 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 	}
 
 	/* TODO: Move to service layer. */
-	private RoomInfo calculateSessionInfo(final ImportExportSession importExportSession, final Room room) {
-		int unreadComments = 0;
-		int numUnanswered = 0;
-		int numAnswers = 0;
-		for (Comment i : importExportSession.getFeedbackQuestions()) {
-			if (!i.isRead()) {
-				unreadComments++;
-			}
-		}
-		for (ImportExportSession.ImportExportContent question : importExportSession.getQuestions()) {
-			numAnswers += question.getAnswers().size();
-			if (question.getAnswers().isEmpty()) {
-				numUnanswered++;
-			}
-		}
-		final RoomInfo info = new RoomInfo(room);
-		info.setNumQuestions(importExportSession.getQuestions().size());
-		info.setNumUnanswered(numUnanswered);
-		info.setNumAnswers(numAnswers);
-		info.setNumInterposed(importExportSession.getFeedbackQuestions().size());
-		info.setNumUnredInterposed(unreadComments);
-		return info;
+	private Room calculateSessionInfo(final ImportExportSession importExportSession, final Room room) {
+		/* FIXME: not yet migrated - move to service layer */
+		throw new UnsupportedOperationException();
+//		int unreadComments = 0;
+//		int numUnanswered = 0;
+//		int numAnswers = 0;
+//		for (Comment i : importExportSession.getFeedbackQuestions()) {
+//			if (!i.isRead()) {
+//				unreadComments++;
+//			}
+//		}
+//		for (ImportExportSession.ImportExportContent question : importExportSession.getQuestions()) {
+//			numAnswers += question.getAnswers().size();
+//			if (question.getAnswers().isEmpty()) {
+//				numUnanswered++;
+//			}
+//		}
+//		RoomStatistics stats = new RoomStatistics();
+//		stats.setContentCount(importExportSession.getQuestions().size());
+//		stats.setAnswerCount(numAnswers);
+//		stats.setUnreadAnswerCount(numUnanswered);
+//		stats.setCommentCount(importExportSession.getFeedbackQuestions().size());
+//		stats.setUnreadCommentCount(unreadComments);
+//
+//		return room;
 	}
 
 	@Override
@@ -365,9 +295,9 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 	}
 
 	@Override
-	public List<RoomInfo> findInfosForPublicPool() {
-		final List<Room> sessions = this.findAllForPublicPool();
-		return getInfosForSessions(sessions);
+	public List<Room> findInfosForPublicPool() {
+		final List<Room> rooms = this.findAllForPublicPool();
+		return attachStatsForRooms(rooms);
 	}
 
 	@Override
@@ -383,27 +313,27 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 
 	/* TODO: Move to service layer. */
 	@Override
-	public List<RoomInfo> findInfosForPublicPoolByUser(final UserAuthentication user) {
-		final List<Room> sessions = this.findForPublicPoolByUser(user);
-		if (sessions.isEmpty()) {
+	public List<Room> findInfosForPublicPoolByUser(final UserAuthentication user) {
+		final List<Room> rooms = this.findForPublicPoolByUser(user);
+		if (rooms.isEmpty()) {
 			return new ArrayList<>();
 		}
-		return getInfosForSessions(sessions);
+		return attachStatsForRooms(rooms);
 	}
 
 	/* TODO: Move to service layer. */
 	@Override
-	public List<RoomInfo> getMySessionsInfo(final UserAuthentication user, final int start, final int limit) {
+	public List<Room> getRoomsWithStatsForUser(final UserAuthentication user, final int start, final int limit) {
 		final List<Room> sessions = this.findByUser(user, start, limit);
 		if (sessions.isEmpty()) {
 			return new ArrayList<>();
 		}
-		return getInfosForSessions(sessions);
+		return attachStatsForRooms(sessions);
 	}
 
 	/* TODO: Move to service layer. */
-	private List<RoomInfo> getInfosForSessions(final List<Room> sessions) {
-		final List<String> sessionIds = sessions.stream().map(Room::getId).collect(Collectors.toList());
+	private List<Room> attachStatsForRooms(final List<Room> rooms) {
+		final List<String> sessionIds = rooms.stream().map(Room::getId).collect(Collectors.toList());
 		final ViewQuery questionCountView = createQuery("by_sessionid").designDocId("_design/Content")
 				.group(true).keys(sessionIds);
 		final ViewQuery answerCountView = createQuery("by_sessionid").designDocId("_design/Answer")
@@ -411,23 +341,23 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 		final ViewQuery commentCountView = createQuery("by_sessionid").designDocId("_design/Comment")
 				.group(true).keys(sessionIds);
 		final ViewQuery unreadCommentCountView = createQuery("by_sessionid_read").designDocId("_design/Comment")
-				.group(true).keys(sessions.stream().map(session -> ComplexKey.of(session.getId(), false)).collect(Collectors.toList()));
+				.group(true).keys(rooms.stream().map(session -> ComplexKey.of(session.getId(), false)).collect(Collectors.toList()));
 
-		return getSessionInfoData(sessions, questionCountView, answerCountView, commentCountView, unreadCommentCountView);
+		return attachStats(rooms, questionCountView, answerCountView, commentCountView, unreadCommentCountView);
 	}
 
 	/* TODO: Move to service layer. */
-	private List<RoomInfo> getInfosForVisitedSessions(final List<Room> sessions, final UserAuthentication user) {
+	public List<Room> getVisitedRoomsWithStatsForUser(final List<Room> rooms, final UserAuthentication user) {
 		final ViewQuery answeredQuestionsView = createQuery("by_user_sessionid").designDocId("_design/Answer")
-				.keys(sessions.stream().map(session -> ComplexKey.of(user.getUsername(), session.getId())).collect(Collectors.toList()));
+				.keys(rooms.stream().map(session -> ComplexKey.of(user.getUsername(), session.getId())).collect(Collectors.toList()));
 		final ViewQuery contentIdsView = createQuery("by_sessionid").designDocId("_design/Content")
-				.keys(sessions.stream().map(Room::getId).collect(Collectors.toList()));
+				.keys(rooms.stream().map(Room::getId).collect(Collectors.toList()));
 
-		return getVisitedSessionInfoData(sessions, answeredQuestionsView, contentIdsView);
+		return attachVisitedRoomStats(rooms, answeredQuestionsView, contentIdsView);
 	}
 
 	/* TODO: Move to service layer. */
-	private List<RoomInfo> getVisitedSessionInfoData(
+	private List<Room> attachVisitedRoomStats(
 			final List<Room> rooms,
 			final ViewQuery answeredQuestionsView,
 			final ViewQuery contentIdsView) {
@@ -474,22 +404,21 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 			unansweredQuestionsCountMap.put(s.getId(), contentIdsInSession.size());
 		}
 
-		final List<RoomInfo> roomInfos = new ArrayList<>();
 		for (final Room room : rooms) {
 			int numUnanswered = 0;
 
 			if (unansweredQuestionsCountMap.containsKey(room.getId())) {
 				numUnanswered = unansweredQuestionsCountMap.get(room.getId());
 			}
-			final RoomInfo info = new RoomInfo(room);
-			info.setNumUnanswered(numUnanswered);
-			roomInfos.add(info);
+			RoomStatistics stats = new RoomStatistics();
+			room.setStatistics(stats);
+			stats.setUnansweredContentCount(numUnanswered);
 		}
-		return roomInfos;
+		return rooms;
 	}
 
 	/* TODO: Move to service layer. */
-	private List<RoomInfo> getSessionInfoData(
+	private List<Room> attachStats(
 			final List<Room> rooms,
 			final ViewQuery questionCountView,
 			final ViewQuery answerCountView,
@@ -508,7 +437,6 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 				.stream().map(row -> new AbstractMap.SimpleImmutableEntry<>(row.getKey(), row.getValueAsInt()))
 				.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
 
-		final List<RoomInfo> roomInfos = new ArrayList<>();
 		for (final Room room : rooms) {
 			int numQuestions = 0;
 			int numAnswers = 0;
@@ -527,14 +455,14 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 				numUnreadComments = unreadCommentCountMap.get(room.getId());
 			}
 
-			final RoomInfo info = new RoomInfo(room);
-			info.setNumQuestions(numQuestions);
-			info.setNumAnswers(numAnswers);
-			info.setNumInterposed(numComments);
-			info.setNumUnredInterposed(numUnreadComments);
-			roomInfos.add(info);
+			final RoomStatistics stats = new RoomStatistics();
+			room.setStatistics(stats);
+			stats.setContentCount(numQuestions);
+			stats.setAnswerCount(numAnswers);
+			stats.setCommentCount(numComments);
+			stats.setUnreadCommentCount(numUnreadComments);
 		}
-		return roomInfos;
+		return rooms;
 	}
 
 	/* TODO: Move to service layer. */
@@ -555,7 +483,8 @@ public class CouchDbRoomRepository extends CouchDbCrudRepository<Room> implement
 
 			loggedIn.setUser(user.getUsername());
 			loggedIn.setSessionId(room.getId());
-			loggedIn.addVisitedSession(room);
+			/* FIXME: migrate */
+			//loggedIn.addVisitedSession(room);
 			loggedIn.updateTimestamp();
 
 			if (loggedIn.getId() == null) {
diff --git a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbSessionStatisticsRepository.java b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbSessionStatisticsRepository.java
index 7e30cc936f7496e274d50c5fa05c3d59d21b5360..ff689d905d7edf936157a8ca08f9355adf6cb44d 100644
--- a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbSessionStatisticsRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbSessionStatisticsRepository.java
@@ -1,9 +1,9 @@
 package de.thm.arsnova.persistance.couchdb;
 
 import com.fasterxml.jackson.databind.JsonNode;
-import de.thm.arsnova.services.score.Score;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.persistance.SessionStatisticsRepository;
+import de.thm.arsnova.services.score.Score;
 import org.ektorp.ComplexKey;
 import org.ektorp.CouchDbConnector;
 import org.ektorp.ViewResult;
diff --git a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbUserRepository.java b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbUserRepository.java
index a9fda249eb67c8bcdaa3e99b391c2b0036ec2f67..0e8f67c37a08f6877d9e9de442f96a726a10b636 100644
--- a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbUserRepository.java
+++ b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbUserRepository.java
@@ -18,7 +18,7 @@
 package de.thm.arsnova.persistance.couchdb;
 
 import com.google.common.collect.Lists;
-import de.thm.arsnova.entities.migration.v2.DbUser;
+import de.thm.arsnova.entities.UserProfile;
 import de.thm.arsnova.persistance.UserRepository;
 import org.ektorp.BulkDeleteDocument;
 import org.ektorp.CouchDbConnector;
@@ -32,13 +32,13 @@ import org.slf4j.LoggerFactory;
 import java.util.ArrayList;
 import java.util.List;
 
-public class CouchDbUserRepository extends CouchDbCrudRepository<DbUser> implements UserRepository {
+public class CouchDbUserRepository extends CouchDbCrudRepository<UserProfile> implements UserRepository {
 	private static final int BULK_PARTITION_SIZE = 500;
 
 	private static final Logger logger = LoggerFactory.getLogger(CouchDbUserRepository.class);
 
 	public CouchDbUserRepository(final CouchDbConnector db, final boolean createIfNotExists) {
-		super(DbUser.class, db, "by_username", createIfNotExists);
+		super(UserProfile.class, db, "by_username", createIfNotExists);
 	}
 
 	private void log(Object... strings) {
@@ -46,14 +46,14 @@ public class CouchDbUserRepository extends CouchDbCrudRepository<DbUser> impleme
 	}
 
 	@Override
-	public DbUser findByUsername(final String username) {
-		final List<DbUser> users = queryView("by_username", username);
+	public UserProfile findByUsername(final String username) {
+		final List<UserProfile> users = queryView("by_username", username);
 
 		return !users.isEmpty() ? users.get(0) : null;
 	}
 
 	@Override
-	public void delete(final DbUser user) {
+	public void delete(final UserProfile user) {
 		if (db.delete(user) != null) {
 			log("delete", "type", "user", "id", user.getId());
 		} else {
diff --git a/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java b/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java
index 712d6f5180909d2355ca37b41f95fea37047d3f2..921c58c2bfea4fe7e9e76e82517e34ae2c9d8267 100644
--- a/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java
+++ b/src/main/java/de/thm/arsnova/security/ApplicationPermissionEvaluator.java
@@ -17,10 +17,10 @@
  */
 package de.thm.arsnova.security;
 
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Comment;
-import de.thm.arsnova.entities.migration.v2.Content;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Comment;
+import de.thm.arsnova.entities.Content;
 import de.thm.arsnova.persistance.CommentRepository;
 import de.thm.arsnova.persistance.ContentRepository;
 import de.thm.arsnova.persistance.RoomRepository;
@@ -105,18 +105,18 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator {
 	}
 
 	private boolean hasSessionPermission(
-			final String username,
+			final String userId,
 			final Room targetSession,
 			final String permission) {
 		switch (permission) {
 			case "read":
-				return targetSession.isActive();
+				return !targetSession.isClosed();
 			case "create":
-				return !username.isEmpty();
+				return !userId.isEmpty();
 			case "owner":
 			case "update":
 			case "delete":
-				return targetSession.getCreator().equals(username);
+				return targetSession.getOwnerId().equals(userId);
 			default:
 				return false;
 		}
@@ -128,38 +128,38 @@ public class ApplicationPermissionEvaluator implements PermissionEvaluator {
 			final String permission) {
 		switch (permission) {
 			case "read":
-				return roomRepository.findOne(targetContent.getSessionId()).isActive();
+				return !roomRepository.findOne(targetContent.getRoomId()).isClosed();
 			case "create":
 			case "owner":
 			case "update":
 			case "delete":
-				final Room room = roomRepository.findOne(targetContent.getSessionId());
-				return room != null && room.getCreator().equals(username);
+				final Room room = roomRepository.findOne(targetContent.getRoomId());
+				return room != null && room.getOwnerId().equals(username);
 			default:
 				return false;
 		}
 	}
 
 	private boolean hasCommentPermission(
-			final String username,
+			final String userId,
 			final Comment targetComment,
 			final String permission) {
 		switch (permission) {
 			case "create":
-				return !username.isEmpty() && roomRepository.findOne(targetComment.getSessionId()).isActive();
+				return !userId.isEmpty() && !roomRepository.findOne(targetComment.getSessionId()).isClosed();
 			case "owner":
 			case "update":
-				return targetComment.getCreator() != null && targetComment.getCreator().equals(username);
+				return targetComment.getCreatorId() != null && targetComment.getCreatorId().equals(userId);
 			case "read":
 			case "delete":
-				if (targetComment.getCreator() != null && targetComment.getCreator().equals(username)) {
+				if (targetComment.getCreatorId() != null && targetComment.getCreatorId().equals(userId)) {
 					return true;
 				}
 
 				/* Allow reading & deletion by session owner */
 				final Room room = roomRepository.findOne(targetComment.getSessionId());
 
-				return room != null && room.getCreator().equals(username);
+				return room != null && room.getOwnerId().equals(userId);
 			default:
 				return false;
 		}
diff --git a/src/main/java/de/thm/arsnova/security/DbUserDetailsService.java b/src/main/java/de/thm/arsnova/security/DbUserDetailsService.java
index 8e4fde8ed5210e1d4a46a33cf5864eb2645b8634..6fe7a2475edfa7a1f07e4d6ad0338105b281df51 100644
--- a/src/main/java/de/thm/arsnova/security/DbUserDetailsService.java
+++ b/src/main/java/de/thm/arsnova/security/DbUserDetailsService.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.security;
 
-import de.thm.arsnova.entities.migration.v2.DbUser;
+import de.thm.arsnova.entities.UserProfile;
 import de.thm.arsnova.persistance.UserRepository;
 import de.thm.arsnova.services.UserService;
 import org.slf4j.Logger;
@@ -52,8 +52,8 @@ public class DbUserDetailsService implements UserDetailsService {
 	public UserDetails loadUserByUsername(String username) {
 		String uid = username.toLowerCase();
 		logger.debug("Load user: " + uid);
-		DbUser dbUser = userRepository.findByUsername(uid);
-		if (null == dbUser) {
+		UserProfile userProfile = userRepository.findByUsername(uid);
+		if (null == userProfile) {
 			throw new UsernameNotFoundException("User does not exist.");
 		}
 
@@ -64,8 +64,8 @@ public class DbUserDetailsService implements UserDetailsService {
 			grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
 		}
 
-		return new User(uid, dbUser.getPassword(),
-				null == dbUser.getActivationKey(), true, true, true,
-				grantedAuthorities);
+		return new User(uid, userProfile.getAccount().getPassword(),
+				null == userProfile.getAccount().getActivationKey(),
+				true, true, true, grantedAuthorities);
 	}
 }
diff --git a/src/main/java/de/thm/arsnova/services/CommentService.java b/src/main/java/de/thm/arsnova/services/CommentService.java
index 6039ae13c00748bc8d141195df880763f38529c6..38aee41c1442c1fcce40f9c5ab49017884c491b5 100644
--- a/src/main/java/de/thm/arsnova/services/CommentService.java
+++ b/src/main/java/de/thm/arsnova/services/CommentService.java
@@ -1,8 +1,8 @@
 package de.thm.arsnova.services;
 
-import de.thm.arsnova.entities.migration.v2.Comment;
-import de.thm.arsnova.entities.migration.v2.CommentReadingCount;
+import de.thm.arsnova.entities.Comment;
 import de.thm.arsnova.entities.UserAuthentication;
+import de.thm.arsnova.entities.migration.v2.CommentReadingCount;
 
 import java.util.List;
 
diff --git a/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java b/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java
index 04d79af5427037b936d36930c32e14f597840c54..056013b4f8a0bcee57dc87289f458360d4b9e505 100644
--- a/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java
@@ -1,9 +1,9 @@
 package de.thm.arsnova.services;
 
+import de.thm.arsnova.entities.Comment;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Comment;
 import de.thm.arsnova.entities.migration.v2.CommentReadingCount;
-import de.thm.arsnova.entities.migration.v2.Room;
 import de.thm.arsnova.events.DeleteCommentEvent;
 import de.thm.arsnova.events.NewCommentEvent;
 import de.thm.arsnova.exceptions.ForbiddenException;
@@ -18,6 +18,7 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -55,10 +56,10 @@ public class CommentServiceImpl extends DefaultEntityServiceImpl<Comment> implem
 		final Room room = roomRepository.findByKeyword(comment.getSessionId());
 		final UserAuthentication user = userService.getCurrentUser();
 		comment.setSessionId(room.getId());
-		comment.setCreator(user.getUsername());
+		comment.setCreatorId(user.getId());
 		comment.setRead(false);
-		if (comment.getTimestamp() == 0) {
-			comment.setTimestamp(System.currentTimeMillis());
+		if (comment.getTimestamp() == null) {
+			comment.setTimestamp(new Date());
 		}
 		final Comment result = super.create(comment);
 
@@ -92,7 +93,7 @@ public class CommentServiceImpl extends DefaultEntityServiceImpl<Comment> implem
 			throw new UnauthorizedException();
 		}
 		final UserAuthentication user = getCurrentUser();
-		if (room.isCreator(user)) {
+		if (room.getOwnerId().equals(user.getId())) {
 			commentRepository.deleteBySessionId(room.getId());
 		} else {
 			commentRepository.deleteBySessionIdAndUser(room.getId(), user);
@@ -129,7 +130,7 @@ public class CommentServiceImpl extends DefaultEntityServiceImpl<Comment> implem
 	public List<Comment> getBySessionKey(final String sessionKey, final int offset, final int limit) {
 		final Room room = this.getSession(sessionKey);
 		final UserAuthentication user = getCurrentUser();
-		if (room.isCreator(user)) {
+		if (room.getOwnerId().equals(user.getId())) {
 			return commentRepository.findBySessionId(room.getId(), offset, limit);
 		} else {
 			return commentRepository.findBySessionIdAndUser(room.getId(), user, offset, limit);
@@ -154,10 +155,10 @@ public class CommentServiceImpl extends DefaultEntityServiceImpl<Comment> implem
 			throw new NotFoundException();
 		}
 		final Room room = roomRepository.findOne(comment.getSessionId());
-		if (!comment.isCreator(user) && !room.isCreator(user)) {
+		if (!comment.getCreatorId().equals(user.getId()) && !room.getOwnerId().equals(user.getId())) {
 			throw new UnauthorizedException();
 		}
-		if (room.isCreator(user)) {
+		if (room.getOwnerId().equals(user.getId())) {
 			comment.setRead(true);
 			save(comment);
 		}
diff --git a/src/main/java/de/thm/arsnova/services/ContentService.java b/src/main/java/de/thm/arsnova/services/ContentService.java
index 41c1e1024bb04dca8aa2ff6258aeb3f5181ccc6f..a781171558bea622e31f5ed83e69f972a1a9d79c 100644
--- a/src/main/java/de/thm/arsnova/services/ContentService.java
+++ b/src/main/java/de/thm/arsnova/services/ContentService.java
@@ -17,9 +17,10 @@
  */
 package de.thm.arsnova.services;
 
+import de.thm.arsnova.entities.Answer;
+import de.thm.arsnova.entities.AnswerStatistics;
+import de.thm.arsnova.entities.Content;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Answer;
-import de.thm.arsnova.entities.migration.v2.Content;
 
 import java.util.List;
 import java.util.Map;
@@ -38,27 +39,23 @@ public interface ContentService extends EntityService<Content> {
 
 	void delete(String questionId);
 
-	void startNewPiRound(String questionId, UserAuthentication user);
-
-	void startNewPiRoundDelayed(String questionId, int time);
-
-	void cancelPiRoundChange(String questionId);
-
-	void cancelDelayedPiRoundChange(String questionId);
-
-	void resetPiRoundState(String questionId);
-
 	List<String> getUnAnsweredQuestionIds(String sessionKey);
 
 	Answer getMyAnswer(String questionId);
 
 	void getFreetextAnswerAndMarkRead(String answerId, UserAuthentication user);
 
-	List<Answer> getAnswers(String questionId, int piRound, int offset, int limit);
+	AnswerStatistics getStatistics(String contentId, int piRound);
+
+	AnswerStatistics getStatistics(String contentId);
 
-	List<Answer> getAnswers(String questionId, int offset, int limit);
+	AnswerStatistics getAllStatistics(String contentId);
 
-	List<Answer> getAllAnswers(String questionId, int offset, int limit);
+	List<Answer> getAnswers(String contentId, int piRound, int offset, int limit);
+
+	List<Answer> getAnswers(String contentId, int offset, int limit);
+
+	List<Answer> getAllAnswers(String contentId, int offset, int limit);
 
 	int countAnswersByQuestionIdAndRound(String questionId);
 
@@ -136,17 +133,9 @@ public interface ContentService extends EntityService<Content> {
 
 	int countTotalAbstentionsByQuestionId(String questionId);
 
-	String getImage(String questionId, String answerId);
-
 	void setVotingAdmission(String questionId, boolean disableVoting);
 
 	void setVotingAdmissions(String sessionkey, boolean disableVoting, List<Content> contents);
 
 	void setVotingAdmissionForAllQuestions(String sessionkey, boolean disableVoting);
-
-	String getQuestionImage(String questionId);
-
-	String getQuestionFcImage(String questionId);
-
-	List<Content> replaceImageData(List<Content> contents);
 }
diff --git a/src/main/java/de/thm/arsnova/services/ContentServiceImpl.java b/src/main/java/de/thm/arsnova/services/ContentServiceImpl.java
index e1220b27e5e22b7df8858d192d6774663a8c2198..cd33fec3949e2325097e8359389e5650f46caa1f 100644
--- a/src/main/java/de/thm/arsnova/services/ContentServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/ContentServiceImpl.java
@@ -17,26 +17,25 @@
  */
 package de.thm.arsnova.services;
 
+import de.thm.arsnova.entities.Answer;
+import de.thm.arsnova.entities.AnswerStatistics;
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
+import de.thm.arsnova.entities.TextAnswer;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Room;
 import de.thm.arsnova.entities.transport.AnswerQueueElement;
-import de.thm.arsnova.persistance.LogEntryRepository;
-import de.thm.arsnova.persistance.RoomRepository;
-import de.thm.arsnova.util.ImageUtils;
-import de.thm.arsnova.entities.migration.v2.Answer;
-import de.thm.arsnova.entities.migration.v2.Content;
 import de.thm.arsnova.events.*;
-import de.thm.arsnova.exceptions.BadRequestException;
 import de.thm.arsnova.exceptions.NotFoundException;
 import de.thm.arsnova.exceptions.UnauthorizedException;
 import de.thm.arsnova.persistance.AnswerRepository;
 import de.thm.arsnova.persistance.ContentRepository;
+import de.thm.arsnova.persistance.LogEntryRepository;
+import de.thm.arsnova.persistance.RoomRepository;
 import org.ektorp.DbAccessException;
 import org.ektorp.DocumentNotFoundException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.CachePut;
 import org.springframework.cache.annotation.Cacheable;
@@ -54,8 +53,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Queue;
-import java.util.Timer;
-import java.util.TimerTask;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.stream.Collectors;
 
@@ -74,17 +71,10 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 
 	private AnswerRepository answerRepository;
 
-	private ImageUtils imageUtils;
-
-	@Value("${upload.filesize_b}")
-	private int uploadFileSizeByte;
-
 	private ApplicationEventPublisher publisher;
 
 	private static final Logger logger = LoggerFactory.getLogger(ContentServiceImpl.class);
 
-	private HashMap<String, Timer> timerList = new HashMap<>();
-
 	private final Queue<AnswerQueueElement> answerQueue = new ConcurrentLinkedQueue<>();
 
 	public ContentServiceImpl(
@@ -93,7 +83,6 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 			RoomRepository roomRepository,
 			LogEntryRepository dbLogger,
 			UserService userService,
-			ImageUtils imageUtils,
 			@Qualifier("defaultJsonMessageConverter") MappingJackson2HttpMessageConverter jackson2HttpMessageConverter) {
 		super(Content.class, repository, jackson2HttpMessageConverter.getObjectMapper());
 		this.contentRepository = repository;
@@ -101,7 +90,6 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 		this.roomRepository = roomRepository;
 		this.dbLogger = dbLogger;
 		this.userService = userService;
-		this.imageUtils = imageUtils;
 	}
 
 	@Scheduled(fixedDelay = 5000)
@@ -136,16 +124,15 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	public Content get(final String id) {
 		try {
 			final Content content = super.get(id);
-			if (!"freetext".equals(content.getQuestionType()) && 0 == content.getPiRound()) {
+			if (!"freetext".equals(content.getFormat()) && 0 == content.getState().getRound()) {
 			/* needed for legacy questions whose piRound property has not been set */
-				content.setPiRound(1);
+				content.getState().setRound(1);
 			}
-			content.updateRoundManagementState();
 			//content.setSessionKeyword(roomRepository.getSessionFromId(content.getRoomId()).getKeyword());
 
 			return content;
 		} catch (final DocumentNotFoundException e) {
-			logger.error("Could not get question {}.", id, e);
+			logger.error("Could not get content {}.", id, e);
 		}
 
 		return null;
@@ -153,12 +140,12 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 
 	@Override
 	@Caching(evict = {@CacheEvict(value = "contentlists", key = "#sessionId"),
-			@CacheEvict(value = "lecturecontentlists", key = "#sessionId", condition = "#content.getQuestionVariant().equals('lecture')"),
-			@CacheEvict(value = "preparationcontentlists", key = "#sessionId", condition = "#content.getQuestionVariant().equals('preparation')"),
-			@CacheEvict(value = "flashcardcontentlists", key = "#sessionId", condition = "#content.getQuestionVariant().equals('flashcard')") },
+			@CacheEvict(value = "lecturecontentlists", key = "#sessionId", condition = "#content.getGroup().equals('lecture')"),
+			@CacheEvict(value = "preparationcontentlists", key = "#sessionId", condition = "#content.getGroup().equals('preparation')"),
+			@CacheEvict(value = "flashcardcontentlists", key = "#sessionId", condition = "#content.getGroup().equals('flashcard')") },
 			put = {@CachePut(value = "contents", key = "#content.id")})
 	public Content save(final String sessionId, final Content content) {
-		content.setSessionId(sessionId);
+		content.setRoomId(sessionId);
 		try {
 			contentRepository.save(content);
 
@@ -174,9 +161,9 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	@PreAuthorize("isAuthenticated()")
 	@Caching(evict = {
 			@CacheEvict(value = "contentlists", allEntries = true),
-			@CacheEvict(value = "lecturecontentlists", allEntries = true, condition = "#content.getQuestionVariant().equals('lecture')"),
-			@CacheEvict(value = "preparationcontentlists", allEntries = true, condition = "#content.getQuestionVariant().equals('preparation')"),
-			@CacheEvict(value = "flashcardcontentlists", allEntries = true, condition = "#content.getQuestionVariant().equals('flashcard')") },
+			@CacheEvict(value = "lecturecontentlists", allEntries = true, condition = "#content.getGroup().equals('lecture')"),
+			@CacheEvict(value = "preparationcontentlists", allEntries = true, condition = "#content.getGroup().equals('preparation')"),
+			@CacheEvict(value = "flashcardcontentlists", allEntries = true, condition = "#content.getGroup().equals('flashcard')") },
 			put = {@CachePut(value = "contents", key = "#content.id")})
 	public Content update(final Content content) {
 		final UserAuthentication user = userService.getCurrentUser();
@@ -185,26 +172,25 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 			throw new NotFoundException();
 		}
 
-		final Room room = roomRepository.findOne(content.getSessionId());
-		if (user == null || room == null || !room.isCreator(user)) {
+		final Room room = roomRepository.findOne(content.getRoomId());
+		if (user == null || room == null || !room.getOwnerId().equals(user.getId())) {
 			throw new UnauthorizedException();
 		}
 
-		if ("freetext".equals(content.getQuestionType())) {
-			content.setPiRound(0);
-		} else if (content.getPiRound() < 1 || content.getPiRound() > 2) {
-			content.setPiRound(oldContent.getPiRound() > 0 ? oldContent.getPiRound() : 1);
+		if ("freetext".equals(content.getFormat())) {
+			content.getState().setRound(0);
+		} else if (content.getState().getRound() < 1 || content.getState().getRound() > 2) {
+			content.getState().setRound(oldContent.getState().getRound() > 0 ? oldContent.getState().getRound() : 1);
 		}
 
 		content.setId(oldContent.getId());
 		content.setRevision(oldContent.getRevision());
-		content.updateRoundManagementState();
 		contentRepository.save(content);
 
-		if (!oldContent.isActive() && content.isActive()) {
+		if (!oldContent.getState().isVisible() && content.getState().isVisible()) {
 			final UnlockQuestionEvent event = new UnlockQuestionEvent(this, room, content);
 			this.publisher.publishEvent(event);
-		} else if (oldContent.isActive() && !content.isActive()) {
+		} else if (oldContent.getState().isVisible() && !content.getState().isVisible()) {
 			final LockQuestionEvent event = new LockQuestionEvent(this, room, content);
 			this.publisher.publishEvent(event);
 		}
@@ -218,7 +204,7 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	public List<Content> getBySessionKey(final String sessionkey) {
 		final Room room = getSession(sessionkey);
 		final UserAuthentication user = userService.getCurrentUser();
-		if (room.isCreator(user)) {
+		if (room.getOwnerId().equals(user.getId())) {
 			return contentRepository.findBySessionIdForSpeaker(room.getId());
 		} else {
 			return contentRepository.findBySessionIdForUsers(room.getId());
@@ -236,18 +222,18 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	@Override
 	@PreAuthorize("hasPermission(#content.getSessionKeyword(), 'session', 'owner')")
 	public Content save(final Content content) {
-		final Room room = roomRepository.findByKeyword(content.getSessionKeyword());
-		content.setSessionId(room.getId());
-		content.setTimestamp(System.currentTimeMillis() / 1000L);
-
-		if ("freetext".equals(content.getQuestionType())) {
-			content.setPiRound(0);
-		} else if (content.getPiRound() < 1 || content.getPiRound() > 2) {
-			content.setPiRound(1);
+		final Room room = roomRepository.findOne(content.getRoomId());
+		content.setTimestamp(new Date());
+
+		if ("freetext".equals(content.getFormat())) {
+			content.getState().setRound(0);
+		} else if (content.getState().getRound() < 1 || content.getState().getRound() > 2) {
+			content.getState().setRound(1);
 		}
 
+		/* FIXME: migrate
 		// convert imageurl to base64 if neccessary
-		if ("grid".equals(content.getQuestionType()) && !content.getImage().startsWith("http")) {
+		if ("grid".equals(content.getFormat()) && !content.getImage().startsWith("http")) {
 			// base64 adds offset to filesize, formula taken from: http://en.wikipedia.org/wiki/Base64#MIME
 			final int fileSize = (int) ((content.getImage().length() - 814) / 1.37);
 			if (fileSize > uploadFileSizeByte) {
@@ -255,6 +241,7 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 				throw new BadRequestException();
 			}
 		}
+		*/
 
 		final Content result = save(room.getId(), content);
 
@@ -271,16 +258,16 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 			@CacheEvict("answerlists"),
 			@CacheEvict(value = "contents", key = "#contentId"),
 			@CacheEvict(value = "contentlists", allEntries = true),
-			@CacheEvict(value = "lecturecontentlists", allEntries = true /*, condition = "#content.getQuestionVariant().equals('lecture')"*/),
-			@CacheEvict(value = "preparationcontentlists", allEntries = true /*, condition = "#content.getQuestionVariant().equals('preparation')"*/),
-			@CacheEvict(value = "flashcardcontentlists", allEntries = true /*, condition = "#content.getQuestionVariant().equals('flashcard')"*/) })
+			@CacheEvict(value = "lecturecontentlists", allEntries = true /*, condition = "#content.getGroup().equals('lecture')"*/),
+			@CacheEvict(value = "preparationcontentlists", allEntries = true /*, condition = "#content.getGroup().equals('preparation')"*/),
+			@CacheEvict(value = "flashcardcontentlists", allEntries = true /*, condition = "#content.getGroup().equals('flashcard')"*/) })
 	public void delete(final String contentId) {
 		final Content content = contentRepository.findOne(contentId);
 		if (content == null) {
 			throw new NotFoundException();
 		}
 
-		final Room room = roomRepository.findOne(content.getSessionId());
+		final Room room = roomRepository.findOne(content.getRoomId());
 		if (room == null) {
 			throw new UnauthorizedException();
 		}
@@ -350,110 +337,14 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	}
 
 	@Override
-	@PreAuthorize("isAuthenticated() and hasPermission(#questionId, 'content', 'owner')")
-	public void startNewPiRound(final String questionId, UserAuthentication user) {
-		final Content content = contentRepository.findOne(questionId);
-		final Room room = roomRepository.findOne(content.getSessionId());
-
-		if (null == user) {
-			user = userService.getCurrentUser();
-		}
-
-		cancelDelayedPiRoundChange(questionId);
-
-		content.setPiRoundEndTime(0);
-		content.setVotingDisabled(true);
-		content.updateRoundManagementState();
-		update(content);
-
-		this.publisher.publishEvent(new PiRoundEndEvent(this, room, content));
-	}
-
-	@Override
-	@PreAuthorize("hasPermission(#questionId, 'content', 'owner')")
-	public void startNewPiRoundDelayed(final String questionId, final int time) {
-		final ContentService contentService = this;
-		final UserAuthentication user = userService.getCurrentUser();
-		final Content content = contentRepository.findOne(questionId);
-		final Room room = roomRepository.findOne(content.getSessionId());
-
-		final Date date = new Date();
-		final Timer timer = new Timer();
-		final Date endDate = new Date(date.getTime() + (time * 1000));
-		content.updateRoundStartVariables(date, endDate);
-		update(content);
-
-		this.publisher.publishEvent(new PiRoundDelayedStartEvent(this, room, content));
-		timerList.put(questionId, timer);
-
-		timer.schedule(new TimerTask() {
-			@Override
-			public void run() {
-				contentService.startNewPiRound(questionId, user);
-			}
-		}, endDate);
-	}
-
-	@Override
-	@PreAuthorize("hasPermission(#questionId, 'content', 'owner')")
-	public void cancelPiRoundChange(final String questionId) {
-		final Content content = contentRepository.findOne(questionId);
-		final Room room = roomRepository.findOne(content.getSessionId());
-
-		cancelDelayedPiRoundChange(questionId);
-		content.resetRoundManagementState();
-
-		if (0 == content.getPiRound() || 1 == content.getPiRound()) {
-			content.setPiRoundFinished(false);
-		} else {
-			content.setPiRound(1);
-			content.setPiRoundFinished(true);
-		}
-
-		update(content);
-		this.publisher.publishEvent(new PiRoundCancelEvent(this, room, content));
-	}
-
-	@Override
-	public void cancelDelayedPiRoundChange(final String questionId) {
-		Timer timer = timerList.get(questionId);
-
-		if (null != timer) {
-			timer.cancel();
-			timerList.remove(questionId);
-			timer.purge();
-		}
-	}
-
-	@Override
-	@PreAuthorize("hasPermission(#questionId, 'content', 'owner')")
-	@CacheEvict("answerlists")
-	public void resetPiRoundState(final String questionId) {
-		final Content content = contentRepository.findOne(questionId);
-		final Room room = roomRepository.findOne(content.getSessionId());
-		cancelDelayedPiRoundChange(questionId);
-
-		if ("freetext".equals(content.getQuestionType())) {
-			content.setPiRound(0);
-		} else {
-			content.setPiRound(1);
-		}
-
-		content.resetRoundManagementState();
-		answerRepository.deleteByContentId(content.getId());
-		update(content);
-		this.publisher.publishEvent(new PiRoundResetEvent(this, room, content));
-	}
+	@PreAuthorize("hasPermission(#contentId, 'content', 'owner')")
+	public void setVotingAdmission(final String contentId, final boolean disableVoting) {
+		final Content content = contentRepository.findOne(contentId);
+		final Room room = roomRepository.findOne(content.getRoomId());
+		content.getState().setResponsesEnabled(!disableVoting);
 
-	@Override
-	@PreAuthorize("hasPermission(#questionId, 'content', 'owner')")
-	public void setVotingAdmission(final String questionId, final boolean disableVoting) {
-		final Content content = contentRepository.findOne(questionId);
-		final Room room = roomRepository.findOne(content.getSessionId());
-		content.setVotingDisabled(disableVoting);
-
-		if (!disableVoting && !content.isActive()) {
-			content.setActive(true);
+		if (!disableVoting && !content.getState().isVisible()) {
+			content.getState().setVisible(true);
 			update(content);
 		} else {
 			update(content);
@@ -477,12 +368,12 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	public void setVotingAdmissions(final String sessionkey, final boolean disableVoting, List<Content> contents) {
 		final UserAuthentication user = getCurrentUser();
 		final Room room = getSession(sessionkey);
-		if (!room.isCreator(user)) {
+		if (!room.getOwnerId().equals(user.getId())) {
 			throw new UnauthorizedException();
 		}
 		for (final Content q : contents) {
-			if (!"flashcard".equals(q.getQuestionType())) {
-				q.setVotingDisabled(disableVoting);
+			if (!"flashcard".equals(q.getRoomId())) {
+				q.getState().setResponsesEnabled(!disableVoting);
 			}
 		}
 		ArsnovaEvent event;
@@ -499,7 +390,7 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	public void setVotingAdmissionForAllQuestions(final String sessionkey, final boolean disableVoting) {
 		final UserAuthentication user = getCurrentUser();
 		final Room room = getSession(sessionkey);
-		if (!room.isCreator(user)) {
+		if (!room.getOwnerId().equals(user.getId())) {
 			throw new UnauthorizedException();
 		}
 		final List<Content> contents = contentRepository.findBySessionId(room.getId());
@@ -509,17 +400,18 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	private Room getSessionWithAuthCheck(final String sessionKeyword) {
 		final UserAuthentication user = userService.getCurrentUser();
 		final Room room = roomRepository.findByKeyword(sessionKeyword);
-		if (user == null || room == null || !room.isCreator(user)) {
+		if (user == null || room == null || !room.getOwnerId().equals(user.getId())) {
 			throw new UnauthorizedException();
 		}
 		return room;
 	}
 
 	@Override
-	@PreAuthorize("hasPermission(#questionId, 'content', 'owner')")
-	public void deleteAnswers(final String questionId) {
-		final Content content = contentRepository.findOne(questionId);
-		content.resetQuestionState();
+	@PreAuthorize("hasPermission(#contentId, 'content', 'owner')")
+	public void deleteAnswers(final String contentId) {
+		final Content content = contentRepository.findOne(contentId);
+		content.resetState();
+		/* FIXME: cancel timer */
 		update(content);
 		answerRepository.deleteByContentId(content.getId());
 	}
@@ -542,89 +434,115 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public Answer getMyAnswer(final String questionId) {
-		final Content content = get(questionId);
+	public Answer getMyAnswer(final String contentId) {
+		final Content content = get(contentId);
 		if (content == null) {
 			throw new NotFoundException();
 		}
-		return answerRepository.findByQuestionIdUserPiRound(questionId, userService.getCurrentUser(), content.getPiRound());
+		return answerRepository.findByQuestionIdUserPiRound(contentId, userService.getCurrentUser(), content.getState().getRound());
 	}
 
 	@Override
 	public void getFreetextAnswerAndMarkRead(final String answerId, final UserAuthentication user) {
 		final Answer answer = answerRepository.findOne(answerId);
-		if (answer == null) {
+		if (!(answer instanceof TextAnswer)) {
 			throw new NotFoundException();
 		}
-		if (answer.isRead()) {
+		final TextAnswer textAnswer = (TextAnswer) answer;
+		if (textAnswer.isRead()) {
 			return;
 		}
-		final Room room = roomRepository.findOne(answer.getSessionId());
-		if (room.isCreator(user)) {
-			answer.setRead(true);
-			answerRepository.save(answer);
+		final Room room = roomRepository.findOne(textAnswer.getRoomId());
+		if (room.getOwnerId().equals(user.getId())) {
+			textAnswer.setRead(true);
+			answerRepository.save(textAnswer);
 		}
 	}
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public List<Answer> getAnswers(final String questionId, final int piRound, final int offset, final int limit) {
-		final Content content = contentRepository.findOne(questionId);
+	public AnswerStatistics getStatistics(final String contentId, final int piRound) {
+		final Content content = contentRepository.findOne(contentId);
 		if (content == null) {
 			throw new NotFoundException();
 		}
-		return "freetext".equals(content.getQuestionType())
-				? getFreetextAnswersByQuestionId(questionId, offset, limit)
-						: answerRepository.findByContentIdPiRound(content.getId(), piRound);
+
+		return answerRepository.findByContentIdPiRound(content.getId(), piRound);
 	}
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public List<Answer> getAnswers(final String questionId, final int offset, final int limit) {
-		final Content content = get(questionId);
+	public AnswerStatistics getStatistics(final String contentId) {
+		final Content content = get(contentId);
 		if (content == null) {
 			throw new NotFoundException();
 		}
-		if ("freetext".equals(content.getQuestionType())) {
-			return getFreetextAnswersByQuestionId(questionId, offset, limit);
-		} else {
-			return answerRepository.findByContentIdPiRound(content.getId(), content.getPiRound());
+
+		return getStatistics(content.getId(), content.getState().getRound());
+	}
+
+	@Override
+	@PreAuthorize("isAuthenticated()")
+	public AnswerStatistics getAllStatistics(final String contentId) {
+		final Content content = get(contentId);
+		if (content == null) {
+			throw new NotFoundException();
 		}
+		AnswerStatistics stats = answerRepository.findByContentIdPiRound(content.getId(), 1);
+		AnswerStatistics stats2 = answerRepository.findByContentIdPiRound(content.getId(), 2);
+		stats.getRoundStatistics().add(stats2.getRoundStatistics().get(0));
+
+		return stats;
 	}
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public List<Answer> getAllAnswers(final String questionId, final int offset, final int limit) {
-		final Content content = get(questionId);
+	public List<Answer> getAnswers(final String contentId, final int piRound, final int offset, final int limit) {
+		/* FIXME: round support not implemented */
+		final Content content = contentRepository.findOne(contentId);
 		if (content == null) {
 			throw new NotFoundException();
 		}
-		if ("freetext".equals(content.getQuestionType())) {
-			return getFreetextAnswersByQuestionId(questionId, offset, limit);
-		} else {
-			return answerRepository.findByContentId(content.getId());
+
+		return getFreetextAnswersByQuestionId(contentId, offset, limit);
+	}
+
+	@Override
+	@PreAuthorize("isAuthenticated()")
+	public List<Answer> getAnswers(final String contentId, final int offset, final int limit) {
+		return getAnswers(contentId, 0, offset, limit);
+	}
+
+	@Override
+	@PreAuthorize("isAuthenticated()")
+	public List<Answer> getAllAnswers(final String contentId, final int offset, final int limit) {
+		final Content content = get(contentId);
+		if (content == null) {
+			throw new NotFoundException();
 		}
+
+		return getFreetextAnswersByQuestionId(contentId, offset, limit);
 	}
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public int countAnswersByQuestionIdAndRound(final String questionId) {
-		final Content content = get(questionId);
+	public int countAnswersByQuestionIdAndRound(final String contentId) {
+		final Content content = get(contentId);
 		if (content == null) {
 			return 0;
 		}
 
-		if ("freetext".equals(content.getQuestionType())) {
+		if ("freetext".equals(content.getFormat())) {
 			return answerRepository.countByContentId(content.getId());
 		} else {
-			return answerRepository.countByContentIdRound(content.getId(), content.getPiRound());
+			return answerRepository.countByContentIdRound(content.getId(), content.getState().getRound());
 		}
 	}
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public int countAnswersByQuestionIdAndRound(final String questionId, final int piRound) {
-		final Content content = get(questionId);
+	public int countAnswersByQuestionIdAndRound(final String contentId, final int piRound) {
+		final Content content = get(contentId);
 		if (content == null) {
 			return 0;
 		}
@@ -634,19 +552,19 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public int countTotalAbstentionsByQuestionId(final String questionId) {
-		final Content content = get(questionId);
+	public int countTotalAbstentionsByQuestionId(final String contentId) {
+		final Content content = get(contentId);
 		if (content == null) {
 			return 0;
 		}
 
-		return answerRepository.countByContentId(questionId);
+		return answerRepository.countByContentId(contentId);
 	}
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public int countTotalAnswersByQuestionId(final String questionId) {
-		final Content content = get(questionId);
+	public int countTotalAnswersByQuestionId(final String contentId) {
+		final Content content = get(contentId);
 		if (content == null) {
 			return 0;
 		}
@@ -656,15 +574,11 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public List<Answer> getFreetextAnswersByQuestionId(final String questionId, final int offset, final int limit) {
-		final List<Answer> answers = answerRepository.findByContentId(questionId, offset, limit);
+	public List<Answer> getFreetextAnswersByQuestionId(final String contentId, final int offset, final int limit) {
+		final List<Answer> answers = answerRepository.findByContentId(contentId, offset, limit);
 		if (answers == null) {
 			throw new NotFoundException();
 		}
-		/* Remove user for privacy concerns */
-		for (Answer answer : answers) {
-			answer.setUser(null);
-		}
 
 		return answers;
 	}
@@ -675,27 +589,27 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 		final Room room = getSession(sessionKey);
 		// Load contents first because we are only interested in answers of the latest piRound.
 		final List<Content> contents = getBySessionKey(sessionKey);
-		final Map<String, Content> questionIdToQuestion = new HashMap<>();
+		final Map<String, Content> contentIdToContent = new HashMap<>();
 		for (final Content content : contents) {
-			questionIdToQuestion.put(content.getId(), content);
+			contentIdToContent.put(content.getId(), content);
 		}
 
-		/* filter answers by active piRound per question */
+		/* filter answers by active piRound per content */
 		final List<Answer> answers = answerRepository.findByUserSessionId(userService.getCurrentUser(), room.getId());
 		final List<Answer> filteredAnswers = new ArrayList<>();
 		for (final Answer answer : answers) {
-			final Content content = questionIdToQuestion.get(answer.getQuestionId());
+			final Content content = contentIdToContent.get(answer.getContentId());
 			if (content == null) {
 				// Content is not present. Most likely it has been locked by the
 				// Room's creator. Locked Questions do not appear in this list.
 				continue;
 			}
-			if (0 == answer.getPiRound() && !"freetext".equals(content.getQuestionType())) {
-				answer.setPiRound(1);
+			if (0 == answer.getRound() && !"freetext".equals(content.getFormat())) {
+				answer.setRound(1);
 			}
 
 			// discard all answers that aren't in the same piRound as the content
-			if (answer.getPiRound() == content.getPiRound()) {
+			if (answer.getRound() == content.getState().getRound()) {
 				filteredAnswers.add(answer);
 			}
 		}
@@ -718,19 +632,21 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 		if (content == null) {
 			throw new NotFoundException();
 		}
-		final Room room = roomRepository.findOne(content.getSessionId());
+		final Room room = roomRepository.findOne(content.getRoomId());
+
+		answer.setCreatorId(user.getId());
+		answer.setContentId(content.getId());
+		answer.setRoomId(room.getId());
 
-		answer.setUser(user.getUsername());
-		answer.setQuestionId(content.getId());
-		answer.setSessionId(room.getId());
-		answer.setQuestionVariant(content.getQuestionVariant());
+		/* FIXME: migrate
 		answer.setQuestionValue(content.calculateValue(answer));
-		answer.setTimestamp(new Date().getTime());
+		*/
 
-		if ("freetext".equals(content.getQuestionType())) {
-			answer.setPiRound(0);
+		if ("freetext".equals(content.getFormat())) {
+			answer.setRound(0);
+			/* FIXME: migrate
 			imageUtils.generateThumbnailImage(answer);
-			if (content.isFixedAnswer() && content.getText() != null) {
+			if (content.isFixedAnswer() && content.getBody() != null) {
 				answer.setAnswerTextRaw(answer.getAnswerText());
 
 				if (content.isStrictMode()) {
@@ -739,8 +655,9 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 				answer.setQuestionValue(content.evaluateCorrectAnswerFixedText(answer.getAnswerTextRaw()));
 				answer.setSuccessfulFreeTextAnswer(content.isSuccessfulFreeTextAnswer(answer.getAnswerTextRaw()));
 			}
+			*/
 		} else {
-			answer.setPiRound(content.getPiRound());
+			answer.setRound(content.getState().getRound());
 		}
 
 		this.answerQueue.offer(new AnswerQueueElement(room, content, answer, user));
@@ -753,20 +670,22 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	@CacheEvict(value = "answerlists", allEntries = true)
 	public Answer updateAnswer(final Answer answer) {
 		final UserAuthentication user = userService.getCurrentUser();
-		final Answer realAnswer = this.getMyAnswer(answer.getQuestionId());
-		if (user == null || realAnswer == null || !user.getUsername().equals(realAnswer.getUser())) {
+		final Answer realAnswer = this.getMyAnswer(answer.getContentId());
+		if (user == null || realAnswer == null || !user.getId().equals(realAnswer.getCreatorId())) {
 			throw new UnauthorizedException();
 		}
 
-		final Content content = get(answer.getQuestionId());
-		if ("freetext".equals(content.getQuestionType())) {
+		final Content content = get(answer.getContentId());
+		/* FIXME: migrate
+		if ("freetext".equals(content.getFormat())) {
 			imageUtils.generateThumbnailImage(realAnswer);
 			content.checkTextStrictOptions(realAnswer);
 		}
-		final Room room = roomRepository.findOne(content.getSessionId());
-		answer.setUser(user.getUsername());
-		answer.setQuestionId(content.getId());
-		answer.setSessionId(room.getId());
+		*/
+		final Room room = roomRepository.findOne(content.getRoomId());
+		answer.setCreatorId(user.getId());
+		answer.setContentId(content.getId());
+		answer.setRoomId(room.getId());
 		answerRepository.save(realAnswer);
 		this.publisher.publishEvent(new NewAnswerEvent(this, room, answer, user, content));
 
@@ -776,14 +695,14 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	@Override
 	@PreAuthorize("isAuthenticated()")
 	@CacheEvict(value = "answerlists", allEntries = true)
-	public void deleteAnswer(final String questionId, final String answerId) {
-		final Content content = contentRepository.findOne(questionId);
+	public void deleteAnswer(final String contentId, final String answerId) {
+		final Content content = contentRepository.findOne(contentId);
 		if (content == null) {
 			throw new NotFoundException();
 		}
 		final UserAuthentication user = userService.getCurrentUser();
-		final Room room = roomRepository.findOne(content.getSessionId());
-		if (user == null || room == null || !room.isCreator(user)) {
+		final Room room = roomRepository.findOne(content.getRoomId());
+		if (user == null || room == null || !room.getOwnerId().equals(user.getId())) {
 			throw new UnauthorizedException();
 		}
 		answerRepository.delete(answerId);
@@ -798,7 +717,7 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	public List<Content> getLectureQuestions(final String sessionkey) {
 		final Room room = getSession(sessionkey);
 		final UserAuthentication user = userService.getCurrentUser();
-		if (room.isCreator(user)) {
+		if (room.getOwnerId().equals(user.getId())) {
 			return contentRepository.findBySessionIdOnlyLectureVariant(room.getId());
 		} else {
 			return contentRepository.findBySessionIdOnlyLectureVariantAndActive(room.getId());
@@ -812,7 +731,7 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	public List<Content> getFlashcards(final String sessionkey) {
 		final Room room = getSession(sessionkey);
 		final UserAuthentication user = userService.getCurrentUser();
-		if (room.isCreator(user)) {
+		if (room.getOwnerId().equals(user.getId())) {
 			return contentRepository.findBySessionIdOnlyFlashcardVariant(room.getId());
 		} else {
 			return contentRepository.findBySessionIdOnlyFlashcardVariantAndActive(room.getId());
@@ -826,25 +745,13 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	public List<Content> getPreparationQuestions(final String sessionkey) {
 		final Room room = getSession(sessionkey);
 		final UserAuthentication user = userService.getCurrentUser();
-		if (room.isCreator(user)) {
+		if (room.getOwnerId().equals(user.getId())) {
 			return contentRepository.findBySessionIdOnlyPreparationVariant(room.getId());
 		} else {
 			return contentRepository.findBySessionIdOnlyPreparationVariantAndActive(room.getId());
 		}
 	}
 
-	@Override
-	@PreAuthorize("isAuthenticated()")
-	public List<Content> replaceImageData(final List<Content> contents) {
-		for (Content q : contents) {
-			if (q.getImage() != null && q.getImage().startsWith("data:image/")) {
-				q.setImage("true");
-			}
-		}
-
-		return contents;
-	}
-
 	private Room getSession(final String sessionkey) {
 		final Room room = roomRepository.findByKeyword(sessionkey);
 		if (room == null) {
@@ -887,17 +794,17 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	}
 
 	@Override
-	public Map<String, Object> countAnswersAndAbstentionsInternal(final String questionId) {
-		final Content content = get(questionId);
+	public Map<String, Object> countAnswersAndAbstentionsInternal(final String contentId) {
+		final Content content = get(contentId);
 		HashMap<String, Object> map = new HashMap<>();
 
 		if (content == null) {
 			return null;
 		}
 
-		map.put("_id", questionId);
-		map.put("answers", answerRepository.countByContentIdRound(content.getId(), content.getPiRound()));
-		map.put("abstentions", answerRepository.countByContentId(questionId));
+		map.put("_id", contentId);
+		map.put("answers", answerRepository.countByContentIdRound(content.getId(), content.getState().getRound()));
+		map.put("abstentions", answerRepository.countByContentId(contentId));
 
 		return map;
 	}
@@ -958,7 +865,7 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 		/* TODO: resolve redundancies */
 		final UserAuthentication user = getCurrentUser();
 		final Room room = getSession(sessionkey);
-		if (!room.isCreator(user)) {
+		if (!room.getOwnerId().equals(user.getId())) {
 			throw new UnauthorizedException();
 		}
 		final List<Content> contents = contentRepository.findBySessionId(room.getId());
@@ -975,11 +882,11 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	public void publishQuestions(final String sessionkey, final boolean publish, List<Content> contents) {
 		final UserAuthentication user = getCurrentUser();
 		final Room room = getSession(sessionkey);
-		if (!room.isCreator(user)) {
+		if (!room.getOwnerId().equals(user.getId())) {
 			throw new UnauthorizedException();
 		}
 		for (final Content content : contents) {
-			content.setActive(publish);
+			content.getState().setVisible(publish);
 		}
 		contentRepository.save(contents);
 		ArsnovaEvent event;
@@ -997,7 +904,7 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	public void deleteAllQuestionsAnswers(final String sessionkey) {
 		final UserAuthentication user = getCurrentUser();
 		final Room room = getSession(sessionkey);
-		if (!room.isCreator(user)) {
+		if (!room.getOwnerId().equals(user.getId())) {
 			throw new UnauthorizedException();
 		}
 
@@ -1009,7 +916,7 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 		this.publisher.publishEvent(new DeleteAllQuestionsAnswersEvent(this, room));
 	}
 
-	/* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */
+	/* TODO: Only evict cache entry for the answer's content. This requires some refactoring. */
 	@Override
 	@PreAuthorize("hasPermission(#sessionkey, 'session', 'owner')")
 	@CacheEvict(value = "answerlists", allEntries = true)
@@ -1024,7 +931,7 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 		this.publisher.publishEvent(new DeleteAllPreparationAnswersEvent(this, room));
 	}
 
-	/* TODO: Only evict cache entry for the answer's question. This requires some refactoring. */
+	/* TODO: Only evict cache entry for the answer's content. This requires some refactoring. */
 	@Override
 	@PreAuthorize("hasPermission(#sessionkey, 'session', 'owner')")
 	@CacheEvict(value = "answerlists", allEntries = true)
@@ -1048,8 +955,8 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	private void resetContentsRoundState(final String sessionId, final List<Content> contents) {
 		for (final Content q : contents) {
 			/* TODO: Check if setting the sessionId is necessary. */
-			q.setSessionId(sessionId);
-			q.resetQuestionState();
+			q.setRoomId(sessionId);
+			q.resetState();
 		}
 		contentRepository.save(contents);
 	}
@@ -1058,47 +965,4 @@ public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implem
 	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
 		this.publisher = publisher;
 	}
-
-	@Override
-	public String getImage(String questionId, String answerId) {
-		final List<Answer> answers = getAnswers(questionId, -1, -1);
-		Answer answer = null;
-
-		for (Answer a : answers) {
-			if (answerId.equals(a.getId())) {
-				answer = a;
-				break;
-			}
-		}
-
-		if (answer == null) {
-			throw new NotFoundException();
-		}
-
-		return answer.getAnswerImage();
-	}
-
-	@Override
-	public String getQuestionImage(String questionId) {
-		Content content = contentRepository.findOne(questionId);
-		String imageData = content.getImage();
-
-		if (imageData == null) {
-			imageData = "";
-		}
-
-		return imageData;
-	}
-
-	@Override
-	public String getQuestionFcImage(String questionId) {
-		Content content = contentRepository.findOne(questionId);
-		String imageData = content.getFcImage();
-
-		if (imageData == null) {
-			imageData = "";
-		}
-
-		return imageData;
-	}
 }
diff --git a/src/main/java/de/thm/arsnova/services/FeedbackServiceImpl.java b/src/main/java/de/thm/arsnova/services/FeedbackServiceImpl.java
index 6da2a04250741a3eb5ac0f6690898e59f7b895d9..81344059cb75648ffb8572e83250dd196ba085db 100644
--- a/src/main/java/de/thm/arsnova/services/FeedbackServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/FeedbackServiceImpl.java
@@ -18,8 +18,8 @@
 package de.thm.arsnova.services;
 
 import de.thm.arsnova.entities.Feedback;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Room;
 import de.thm.arsnova.events.DeleteFeedbackForRoomsEvent;
 import de.thm.arsnova.events.NewFeedbackEvent;
 import de.thm.arsnova.exceptions.NoContentException;
diff --git a/src/main/java/de/thm/arsnova/services/FeedbackStorageService.java b/src/main/java/de/thm/arsnova/services/FeedbackStorageService.java
index c6596607f7c68d698e2399ed2bae544ad174ca46..8dacaafe566615846b33f31732550fc40983eb1e 100644
--- a/src/main/java/de/thm/arsnova/services/FeedbackStorageService.java
+++ b/src/main/java/de/thm/arsnova/services/FeedbackStorageService.java
@@ -1,8 +1,8 @@
 package de.thm.arsnova.services;
 
 import de.thm.arsnova.entities.Feedback;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Room;
 
 import java.util.List;
 import java.util.Map;
diff --git a/src/main/java/de/thm/arsnova/services/FeedbackStorageServiceImpl.java b/src/main/java/de/thm/arsnova/services/FeedbackStorageServiceImpl.java
index 3dda7e4255f82a19fb65efb4c7bf5210841ed2ff..36053e0c37cb5e86649c3bdf348544961c09e402 100644
--- a/src/main/java/de/thm/arsnova/services/FeedbackStorageServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/FeedbackStorageServiceImpl.java
@@ -18,8 +18,8 @@
 package de.thm.arsnova.services;
 
 import de.thm.arsnova.entities.Feedback;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Room;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Isolation;
 import org.springframework.transaction.annotation.Transactional;
@@ -124,7 +124,7 @@ public class FeedbackStorageServiceImpl implements FeedbackStorageService {
 	public Map<Room, List<UserAuthentication>> cleanVotes(final int cleanupFeedbackDelay) {
 		final Map<Room, List<UserAuthentication>> removedFeedbackOfUsersInSession = new HashMap<>();
 		for (final Room room : data.keySet()) {
-			if (room.getFeatures() == null || !room.getFeatures().isLiveClicker()) {
+			if (!room.getSettings().isLivevoteEnabled()) {
 				List<UserAuthentication> affectedUsers = cleanVotesByRoom(room, cleanupFeedbackDelay);
 				if (!affectedUsers.isEmpty()) {
 					removedFeedbackOfUsersInSession.put(room, affectedUsers);
diff --git a/src/main/java/de/thm/arsnova/services/MotdService.java b/src/main/java/de/thm/arsnova/services/MotdService.java
index 10133269968af46dc609fab745f0f4aca3d7729d..e83831bc2863c1252f6e37601afea0c77d0a23f2 100644
--- a/src/main/java/de/thm/arsnova/services/MotdService.java
+++ b/src/main/java/de/thm/arsnova/services/MotdService.java
@@ -17,8 +17,7 @@
  */
 package de.thm.arsnova.services;
 
-import de.thm.arsnova.entities.migration.v2.Motd;
-import de.thm.arsnova.entities.migration.v2.MotdList;
+import de.thm.arsnova.entities.Motd;
 
 import java.util.Date;
 import java.util.List;
@@ -39,23 +38,17 @@ public interface MotdService extends EntityService<Motd> {
 
 	List<Motd> filterMotdsByDate(List<Motd> list, Date clientdate);
 
-	List<Motd> filterMotdsByList(List<Motd> list, MotdList motdList);
+	List<Motd> filterMotdsByList(List<Motd> list, List<String> ids);
 
 	void delete(Motd motd);
 
-	void deleteBySessionKey(final String sessionkey, Motd motd);
+	void deleteBySessionKey(final String sessionId, Motd motd);
 
 	Motd save(Motd motd);
 
-	Motd save(final String sessionkey, final Motd motd);
+	Motd save(final String sessionId, final Motd motd);
 
 	Motd update(Motd motd);
 
 	Motd update(final String sessionkey, Motd motd);
-
-	MotdList getMotdListByUsername(final String username);
-
-	MotdList saveMotdList(MotdList motdList);
-
-	MotdList updateMotdList(MotdList motdList);
 }
diff --git a/src/main/java/de/thm/arsnova/services/MotdServiceImpl.java b/src/main/java/de/thm/arsnova/services/MotdServiceImpl.java
index c1f826901f73a1f9cf61204185957f0e975174ba..059da1149eb3002e91cbd2677e5cb739a19d664f 100644
--- a/src/main/java/de/thm/arsnova/services/MotdServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/MotdServiceImpl.java
@@ -17,16 +17,12 @@
  */
 package de.thm.arsnova.services;
 
-import de.thm.arsnova.entities.migration.v2.Motd;
-import de.thm.arsnova.entities.migration.v2.MotdList;
-import de.thm.arsnova.entities.migration.v2.Room;
-import de.thm.arsnova.entities.UserAuthentication;
+import de.thm.arsnova.entities.Motd;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.exceptions.BadRequestException;
-import de.thm.arsnova.persistance.MotdListRepository;
 import de.thm.arsnova.persistance.MotdRepository;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.CachePut;
 import org.springframework.cache.annotation.Cacheable;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -34,9 +30,9 @@ import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
 import java.util.Date;
-import java.util.HashSet;
 import java.util.List;
-import java.util.StringTokenizer;
+import java.util.stream.Collectors;
+
 /**
  * Performs all question, interposed question, and answer related operations.
  */
@@ -48,17 +44,13 @@ public class MotdServiceImpl extends DefaultEntityServiceImpl<Motd> implements M
 
 	private MotdRepository motdRepository;
 
-	private MotdListRepository motdListRepository;
-
 	public MotdServiceImpl(
 			MotdRepository repository,
-			MotdListRepository motdListRepository,
 			UserService userService,
 			RoomService roomService,
 			@Qualifier("defaultJsonMessageConverter") MappingJackson2HttpMessageConverter jackson2HttpMessageConverter) {
 		super(Motd.class, repository, jackson2HttpMessageConverter.getObjectMapper());
 		this.motdRepository = repository;
-		this.motdListRepository = motdListRepository;
 		this.userService = userService;
 		this.roomService = roomService;
 	}
@@ -77,14 +69,14 @@ public class MotdServiceImpl extends DefaultEntityServiceImpl<Motd> implements M
 
 	@Override
 	@PreAuthorize("hasPermission(#sessionkey, 'session', 'owner')")
-	public List<Motd> getAllSessionMotds(final String sessionkey) {
-		return motdRepository.findBySessionKey(sessionkey);
+	public List<Motd> getAllSessionMotds(final String sessionId) {
+		return motdRepository.findBySessionKey(sessionId);
 	}
 
 	@Override
-	@Cacheable(cacheNames = "motds", key = "('session').concat(#sessionkey)")
-	public List<Motd> getCurrentSessionMotds(final Date clientdate, final String sessionkey) {
-		final List<Motd> motds = motdRepository.findBySessionKey(sessionkey);
+	@Cacheable(cacheNames = "motds", key = "('session').concat(#sessionId)")
+	public List<Motd> getCurrentSessionMotds(final Date clientdate, final String sessionId) {
+		final List<Motd> motds = motdRepository.findBySessionKey(sessionId);
 		return filterMotdsByDate(motds, clientdate);
 	}
 
@@ -115,23 +107,8 @@ public class MotdServiceImpl extends DefaultEntityServiceImpl<Motd> implements M
   }
 
 	@Override
-	public List<Motd> filterMotdsByList(List<Motd> list, MotdList motdlist) {
-		if (motdlist != null && motdlist.getMotdkeys() != null && !motdlist.getMotdkeys().isEmpty()) {
-			List<Motd> returns = new ArrayList<>();
-			HashSet<String> keys = new HashSet<>(500);  // Or a more realistic size
-			StringTokenizer st = new StringTokenizer(motdlist.getMotdkeys(), ",");
-			while (st.hasMoreTokens()) {
-				keys.add(st.nextToken());
-			}
-			for (Motd motd : list) {
-				if (!keys.contains(motd.getMotdkey())) {
-					returns.add(motd);
-				}
-			}
-			return returns;
-		} else {
-			return list;
-		}
+	public List<Motd> filterMotdsByList(List<Motd> list, List<String> ids) {
+		return list.stream().filter(id -> ids.contains(id)).collect(Collectors.toList());
 	}
 
 	@Override
@@ -142,8 +119,8 @@ public class MotdServiceImpl extends DefaultEntityServiceImpl<Motd> implements M
 
 	@Override
 	@PreAuthorize("hasPermission(#sessionkey, 'session', 'owner')")
-	public Motd save(final String sessionkey, final Motd motd) {
-		Room room = roomService.getByKey(sessionkey);
+	public Motd save(final String sessionId, final Motd motd) {
+		Room room = roomService.getByKey(sessionId);
 		motd.setSessionId(room.getId());
 
 		return createOrUpdateMotd(motd);
@@ -161,11 +138,11 @@ public class MotdServiceImpl extends DefaultEntityServiceImpl<Motd> implements M
 		return createOrUpdateMotd(motd);
 	}
 
-	@CacheEvict(cacheNames = "motds", key = "#motd.audience.concat(#motd.sessionkey)")
+	@CacheEvict(cacheNames = "motds", key = "#motd.audience.concat(#motd.sessionId)")
 	private Motd createOrUpdateMotd(final Motd motd) {
-		if (motd.getMotdkey() != null) {
-			Motd oldMotd = motdRepository.findByKey(motd.getMotdkey());
-			if (!(motd.getId().equals(oldMotd.getId()) && motd.getSessionkey().equals(oldMotd.getSessionkey())
+		if (motd.getId() != null) {
+			Motd oldMotd = motdRepository.findOne(motd.getId());
+			if (!(motd.getId().equals(oldMotd.getId()) && motd.getSessionId().equals(oldMotd.getSessionId())
 					&& motd.getAudience().equals(oldMotd.getAudience()))) {
 				throw new BadRequestException();
 			}
@@ -173,9 +150,7 @@ public class MotdServiceImpl extends DefaultEntityServiceImpl<Motd> implements M
 
 		if (null != motd.getId()) {
 			Motd oldMotd = get(motd.getId());
-			motd.setMotdkey(oldMotd.getMotdkey());
-		} else {
-			motd.setMotdkey(roomService.generateKey());
+			motd.setId(oldMotd.getId());
 		}
 		save(motd);
 
@@ -184,46 +159,14 @@ public class MotdServiceImpl extends DefaultEntityServiceImpl<Motd> implements M
 
 	@Override
 	@PreAuthorize("hasPermission('', 'motd', 'admin')")
-	@CacheEvict(cacheNames = "motds", key = "#motd.audience.concat(#motd.sessionkey)")
+	@CacheEvict(cacheNames = "motds", key = "#motd.audience.concat(#motd.sessionId)")
 	public void delete(Motd motd) {
 		motdRepository.delete(motd);
 	}
 
 	@Override
-	@PreAuthorize("hasPermission(#sessionkey, 'session', 'owner')")
-	public void deleteBySessionKey(final String sessionkey, Motd motd) {
+	@PreAuthorize("hasPermission(#sessionId, 'session', 'owner')")
+	public void deleteBySessionKey(final String sessionId, Motd motd) {
 		motdRepository.delete(motd);
 	}
-
-	@Override
-	@PreAuthorize("isAuthenticated()")
-	@Cacheable(cacheNames = "motdlist", key = "#username")
-	public MotdList getMotdListByUsername(final String username) {
-		final UserAuthentication user = userService.getCurrentUser();
-		if (username.equals(user.getUsername()) && !"guest".equals(user.getType())) {
-			return motdListRepository.findByUsername(username);
-		}
-		return null;
-	}
-
-	@Override
-	@PreAuthorize("isAuthenticated()")
-	@CachePut(cacheNames = "motdlist", key = "#motdList.username")
-	public MotdList saveMotdList(MotdList motdList) {
-		final UserAuthentication user = userService.getCurrentUser();
-		if (user.getUsername().equals(motdList.getUsername())) {
-			return motdListRepository.save(motdList);
-		}
-		return null;
-	}
-
-	@Override
-	@PreAuthorize("isAuthenticated()")
-	public MotdList updateMotdList(MotdList motdList) {
-		final UserAuthentication user = userService.getCurrentUser();
-		if (user.getUsername().equals(motdList.getUsername())) {
-			return motdListRepository.save(motdList);
-		}
-		return null;
-	}
 }
diff --git a/src/main/java/de/thm/arsnova/services/RoomService.java b/src/main/java/de/thm/arsnova/services/RoomService.java
index 9bce5c5609a613b3f7d097b480d2c4f74d7bb74d..683fbc7c3dc918f02b84bb88c25f28bb9abf5b24 100644
--- a/src/main/java/de/thm/arsnova/services/RoomService.java
+++ b/src/main/java/de/thm/arsnova/services/RoomService.java
@@ -18,10 +18,8 @@
 package de.thm.arsnova.services;
 
 import de.thm.arsnova.connector.model.Course;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Room;
-import de.thm.arsnova.entities.migration.v2.RoomFeature;
-import de.thm.arsnova.entities.migration.v2.RoomInfo;
 import de.thm.arsnova.entities.transport.ImportExportSession;
 import de.thm.arsnova.entities.transport.ScoreStatistics;
 
@@ -72,23 +70,23 @@ public interface RoomService extends EntityService<Room> {
 
 	ScoreStatistics getMyLearningProgress(String sessionkey, String type, String questionVariant);
 
-	List<RoomInfo> getMySessionsInfo(int offset, int limit);
+	List<Room> getMySessionsInfo(int offset, int limit);
 
-	List<RoomInfo> getPublicPoolSessionsInfo();
+	List<Room> getPublicPoolSessionsInfo();
 
-	List<RoomInfo> getMyPublicPoolSessionsInfo();
+	List<Room> getMyPublicPoolSessionsInfo();
 
-	List<RoomInfo> getMyVisitedSessionsInfo(int offset, int limit);
+	List<Room> getMyVisitedSessionsInfo(int offset, int limit);
 
-	RoomInfo importSession(ImportExportSession session);
+	Room importSession(ImportExportSession session);
 
 	ImportExportSession exportSession(String sessionkey, Boolean withAnswerStatistics, Boolean withFeedbackQuestions);
 
-	RoomInfo copySessionToPublicPool(String sessionkey, de.thm.arsnova.entities.transport.ImportExportSession.PublicPool pp);
+	Room copySessionToPublicPool(String sessionkey, de.thm.arsnova.entities.transport.ImportExportSession.PublicPool pp);
 
-	RoomFeature getFeatures(String sessionkey);
+	Room.Settings getFeatures(String sessionkey);
 
-	RoomFeature updateFeatures(String sessionkey, RoomFeature features);
+	Room.Settings updateFeatures(String sessionkey, Room.Settings settings);
 
 	boolean lockFeedbackInput(String sessionkey, Boolean lock);
 
diff --git a/src/main/java/de/thm/arsnova/services/RoomServiceImpl.java b/src/main/java/de/thm/arsnova/services/RoomServiceImpl.java
index 95798f00a36a5d80ca3ea25df8797d8cfcb5e0cf..db7e23b983afc0b2b272ce6b6636ab86ff003f65 100644
--- a/src/main/java/de/thm/arsnova/services/RoomServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/RoomServiceImpl.java
@@ -17,21 +17,11 @@
  */
 package de.thm.arsnova.services;
 
-import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Room;
-import de.thm.arsnova.persistance.AnswerRepository;
-import de.thm.arsnova.persistance.CommentRepository;
-import de.thm.arsnova.persistance.ContentRepository;
-import de.thm.arsnova.persistance.LogEntryRepository;
-import de.thm.arsnova.persistance.RoomRepository;
-import de.thm.arsnova.util.ImageUtils;
 import de.thm.arsnova.connector.client.ConnectorClient;
 import de.thm.arsnova.connector.model.Course;
-import de.thm.arsnova.services.score.ScoreCalculatorFactory;
-import de.thm.arsnova.services.score.ScoreCalculator;
-import de.thm.arsnova.entities.ScoreOptions;
-import de.thm.arsnova.entities.migration.v2.RoomFeature;
-import de.thm.arsnova.entities.migration.v2.RoomInfo;
+import de.thm.arsnova.entities.Room;
+import de.thm.arsnova.entities.UserAuthentication;
+import de.thm.arsnova.entities.UserProfile;
 import de.thm.arsnova.entities.transport.ImportExportSession;
 import de.thm.arsnova.entities.transport.ScoreStatistics;
 import de.thm.arsnova.events.DeleteRoomEvent;
@@ -40,12 +30,16 @@ import de.thm.arsnova.events.FlipFlashcardsEvent;
 import de.thm.arsnova.events.LockFeedbackEvent;
 import de.thm.arsnova.events.NewRoomEvent;
 import de.thm.arsnova.events.StatusRoomEvent;
-import de.thm.arsnova.exceptions.BadRequestException;
 import de.thm.arsnova.exceptions.ForbiddenException;
 import de.thm.arsnova.exceptions.NotFoundException;
-import de.thm.arsnova.exceptions.PayloadTooLargeException;
+import de.thm.arsnova.persistance.AnswerRepository;
+import de.thm.arsnova.persistance.CommentRepository;
+import de.thm.arsnova.persistance.ContentRepository;
+import de.thm.arsnova.persistance.LogEntryRepository;
+import de.thm.arsnova.persistance.RoomRepository;
 import de.thm.arsnova.persistance.VisitedSessionRepository;
-import org.ektorp.UpdateConflictException;
+import de.thm.arsnova.services.score.ScoreCalculator;
+import de.thm.arsnova.services.score.ScoreCalculatorFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -62,9 +56,12 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Service;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.Date;
 import java.util.List;
 import java.util.UUID;
+import java.util.stream.Collectors;
 
 /**
  * Performs all session related operations.
@@ -95,8 +92,6 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 
 	private ConnectorClient connectorClient;
 
-	private ImageUtils imageUtils;
-
 	@Value("${session.guest-session.cleanup-days:0}")
 	private int guestSessionInactivityThresholdDays;
 
@@ -115,7 +110,6 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 			UserService userService,
 			FeedbackService feedbackService,
 			ScoreCalculatorFactory scoreCalculatorFactory,
-			ImageUtils imageUtils,
 			@Qualifier("defaultJsonMessageConverter") MappingJackson2HttpMessageConverter jackson2HttpMessageConverter) {
 		super(Room.class, repository, jackson2HttpMessageConverter.getObjectMapper());
 		this.roomRepository = repository;
@@ -127,7 +121,6 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 		this.userService = userService;
 		this.feedbackService = feedbackService;
 		this.scoreCalculatorFactory = scoreCalculatorFactory;
-		this.imageUtils = imageUtils;
 	}
 
 	public static class SessionNameComparator implements Comparator<Room>, Serializable {
@@ -139,30 +132,12 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 		}
 	}
 
-	public static class SessionInfoNameComparator implements Comparator<RoomInfo>, Serializable {
-		private static final long serialVersionUID = 1L;
-
-		@Override
-		public int compare(final RoomInfo roomInfo1, final RoomInfo roomInfo2) {
-			return roomInfo1.getName().compareToIgnoreCase(roomInfo2.getName());
-		}
-	}
-
 	public static class SessionShortNameComparator implements Comparator<Room>, Serializable {
 		private static final long serialVersionUID = 1L;
 
 		@Override
 		public int compare(final Room room1, final Room room2) {
-			return room1.getShortName().compareToIgnoreCase(room2.getShortName());
-		}
-	}
-
-	public static class SessionInfoShortNameComparator implements Comparator<RoomInfo>, Serializable {
-		private static final long serialVersionUID = 1L;
-
-		@Override
-		public int compare(final RoomInfo roomInfo1, final RoomInfo roomInfo2) {
-			return roomInfo1.getShortName().compareToIgnoreCase(roomInfo2.getShortName());
+			return room1.getAbbreviation().compareToIgnoreCase(room2.getAbbreviation());
 		}
 	}
 
@@ -221,39 +196,20 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 
 		userService.addUserToSessionBySocketId(socketId, keyword);
 
-		if (room.getCreator().equals(user.getUsername())) {
-			updateSessionOwnerActivity(room);
-		}
 		roomRepository.registerAsOnlineUser(user, room);
 
+		/* FIXME: migrate LMS course support
 		if (connectorClient != null && room.isCourseSession()) {
 			final String courseid = room.getCourseId();
 			if (!connectorClient.getMembership(user.getUsername(), courseid).isMember()) {
 				throw new ForbiddenException("User is no course member.");
 			}
 		}
+		*/
 
 		return room;
 	}
 
-	@CachePut(value = "rooms")
-	private Room updateSessionOwnerActivity(final Room session) {
-		try {
-			/* Do not clutter CouchDB. Only update once every 3 hours. */
-			if (session.getLastOwnerActivity() > System.currentTimeMillis() - 3 * 3600000) {
-				return session;
-			}
-
-			session.setLastOwnerActivity(System.currentTimeMillis());
-			save(session);
-
-			return session;
-		} catch (final UpdateConflictException e) {
-			logger.error("Failed to update lastOwnerActivity for session {}.", session, e);
-			return session;
-		}
-	}
-
 	@Override
 	@PreAuthorize("isAuthenticated()")
 	public Room getByKey(final String keyword) {
@@ -276,19 +232,23 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 		if (room == null) {
 			throw new NotFoundException();
 		}
-		if (!room.isActive()) {
+		if (room.isClosed()) {
 			if (user.hasRole(UserRoomService.Role.STUDENT)) {
 				throw new ForbiddenException("User is not session creator.");
-			} else if (user.hasRole(UserRoomService.Role.SPEAKER) && !room.isCreator(user)) {
+			} else if (user.hasRole(UserRoomService.Role.SPEAKER) && !room.getOwnerId().equals(user.getId())) {
 				throw new ForbiddenException("User is not session creator.");
 			}
 		}
+
+		/* FIXME: migrate LMS course support
 		if (connectorClient != null && room.isCourseSession()) {
 			final String courseid = room.getCourseId();
 			if (!connectorClient.getMembership(user.getUsername(), courseid).isMember()) {
 				throw new ForbiddenException("User is no course member.");
 			}
 		}
+		*/
+
 		return room;
 	}
 
@@ -306,45 +266,56 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public List<RoomInfo> getPublicPoolSessionsInfo() {
+	public List<Room> getPublicPoolSessionsInfo() {
 		return roomRepository.findInfosForPublicPool();
 	}
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public List<RoomInfo> getMyPublicPoolSessionsInfo() {
+	public List<Room> getMyPublicPoolSessionsInfo() {
 		return roomRepository.findInfosForPublicPoolByUser(userService.getCurrentUser());
 	}
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public List<RoomInfo> getMySessionsInfo(final int offset, final int limit) {
+	public List<Room> getMySessionsInfo(final int offset, final int limit) {
 		final UserAuthentication user = userService.getCurrentUser();
-		return roomRepository.getMySessionsInfo(user, offset, limit);
+		return roomRepository.getRoomsWithStatsForUser(user, offset, limit);
 	}
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
 	public List<Room> getMyVisitedSessions(final int offset, final int limit) {
-		return roomRepository.findVisitedByUsername(userService.getCurrentUser().getUsername(), offset, limit);
+		/* TODO: implement pagination */
+		return getUserVisitedSessions(userService.getCurrentUser().getUsername());
 	}
 
 	@Override
 	@PreAuthorize("hasPermission('', 'motd', 'admin')")
 	public List<Room> getUserVisitedSessions(String username) {
-		return roomRepository.findVisitedByUsername(username, 0, 0);
+		UserProfile profile = userService.getByUsername(username);
+		List<String> roomIds = profile.getRoomHistory().stream().map(entry -> entry.getRoomId()).collect(Collectors.toList());
+		roomRepository.findAll(roomIds);
+		List<Room> rooms = new ArrayList<>();
+		roomRepository.findAll(roomIds).forEach(rooms::add);
+
+		return rooms;
 	}
 
 	@Override
 	@PreAuthorize("isAuthenticated()")
-	public List<RoomInfo> getMyVisitedSessionsInfo(final int offset, final int limit) {
-		return roomRepository.findInfoForVisitedByUser(userService.getCurrentUser(), offset, limit);
+	public List<Room> getMyVisitedSessionsInfo(final int offset, final int limit) {
+		List<Room> rooms = getMyVisitedSessions(0, 0);
+		roomRepository.getVisitedRoomsWithStatsForUser(rooms, userService.getCurrentUser());
+
+		return rooms;
 	}
 
 	@Override
 	@PreAuthorize("hasPermission('', 'session', 'create')")
 	@Caching(evict = @CacheEvict(cacheNames = "rooms", key = "#result.keyword"))
 	public Room save(final Room room) {
+		/* FIXME: migrate LMS course support
 		if (connectorClient != null && room.getCourseId() != null) {
 			if (!connectorClient.getMembership(
 					userService.getCurrentUser().getUsername(), room.getCourseId()).isMember()
@@ -352,27 +323,17 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 				throw new ForbiddenException();
 			}
 		}
+		*/
+
 		handleLogo(room);
 
-		// set some default values
-		ScoreOptions lpo = new ScoreOptions();
-		lpo.setType("questions");
-		room.setLearningProgressOptions(lpo);
-
-		RoomFeature sf = new RoomFeature();
-		sf.setLecture(true);
-		sf.setFeedback(true);
-		sf.setInterposed(true);
-		sf.setJitt(true);
-		sf.setLearningProgress(true);
-		sf.setPi(true);
-		room.setFeatures(sf);
-
-		room.setKeyword(generateKey());
-		room.setCreationTime(System.currentTimeMillis());
-		room.setCreator(userService.getCurrentUser().getUsername());
-		room.setActive(true);
-		room.setFeedbackLock(false);
+		Room.Settings sf = room.new Settings();
+		room.setSettings(sf);
+
+		room.setShortId(generateKey());
+		room.setCreationTimestamp(new Date());
+		room.setOwnerId(userService.getCurrentUser().getId());
+		room.setClosed(false);
 
 		final Room result = save(room);
 		this.publisher.publishEvent(new NewRoomEvent(this, result));
@@ -415,7 +376,7 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 	@PreAuthorize("hasPermission(#sessionkey, 'session', 'owner')")
 	public Room setActive(final String sessionkey, final Boolean lock) {
 		final Room room = roomRepository.findByKeyword(sessionkey);
-		room.setActive(lock);
+		room.setClosed(!lock);
 		this.publisher.publishEvent(new StatusRoomEvent(this, room));
 		roomRepository.save(room);
 
@@ -427,26 +388,8 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 	@CachePut(value = "rooms", key = "#room")
 	public Room update(final String sessionkey, final Room room) {
 		final Room existingSession = roomRepository.findByKeyword(sessionkey);
-
-		existingSession.setActive(room.isActive());
-		existingSession.setShortName(room.getShortName());
-		existingSession.setPpAuthorName(room.getPpAuthorName());
-		existingSession.setPpAuthorMail(room.getPpAuthorMail());
-		existingSession.setShortName(room.getShortName());
-		existingSession.setPpAuthorName(room.getPpAuthorName());
-		existingSession.setPpFaculty(room.getPpFaculty());
-		existingSession.setName(room.getName());
-		existingSession.setPpUniversity(room.getPpUniversity());
-		existingSession.setPpDescription(room.getPpDescription());
-		existingSession.setPpLevel(room.getPpLevel());
-		existingSession.setPpLicense(room.getPpLicense());
-		existingSession.setPpSubject(room.getPpSubject());
-		existingSession.setFeedbackLock(room.getFeedbackLock());
-
 		handleLogo(room);
-		existingSession.setPpLogo(room.getPpLogo());
-
-		roomRepository.save(existingSession);
+		update(existingSession, room);
 
 		return room;
 	}
@@ -455,15 +398,7 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 	@PreAuthorize("hasPermission('', 'motd', 'admin')")
 	@Caching(evict = { @CacheEvict("rooms"), @CacheEvict(cacheNames = "rooms", key = "#sessionkey.keyword") })
 	public Room updateCreator(String sessionkey, String newCreator) {
-		final Room room = roomRepository.findByKeyword(sessionkey);
-		if (room == null) {
-			throw new NullPointerException("Could not load session " + sessionkey + ".");
-		}
-
-		room.setCreator(newCreator);
-		save(room);
-
-		return save(room);
+		throw new UnsupportedOperationException("No longer implemented.");
 	}
 
 	/*
@@ -472,7 +407,7 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 	 */
 	@Override
 	public Room updateInternal(final Room room, final UserAuthentication user) {
-		if (room.isCreator(user)) {
+		if (room.getOwnerId().equals(user.getId())) {
 			roomRepository.save(room);
 			return room;
 		}
@@ -516,9 +451,9 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 
 	@Override
 	@PreAuthorize("hasPermission('', 'session', 'create')")
-	public RoomInfo importSession(ImportExportSession importSession) {
+	public Room importSession(ImportExportSession importSession) {
 		final UserAuthentication user = userService.getCurrentUser();
-		final RoomInfo info = roomRepository.importSession(user, importSession);
+		final Room info = roomRepository.importSession(user, importSession);
 		if (info == null) {
 			throw new NullPointerException("Could not import session.");
 		}
@@ -533,7 +468,7 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 
 	@Override
 	@PreAuthorize("hasPermission(#sessionkey, 'session', 'owner')")
-	public RoomInfo copySessionToPublicPool(String sessionkey, de.thm.arsnova.entities.transport.ImportExportSession.PublicPool pp) {
+	public Room copySessionToPublicPool(String sessionkey, de.thm.arsnova.entities.transport.ImportExportSession.PublicPool pp) {
 		ImportExportSession temp = roomRepository.exportSession(sessionkey, false, false);
 		temp.getSession().setPublicPool(pp);
 		temp.getSession().setSessionType("public_pool");
@@ -548,20 +483,20 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 
 	@Override
 	@PreAuthorize("hasPermission(#sessionkey, 'session', 'read')")
-	public RoomFeature getFeatures(String sessionkey) {
-		return roomRepository.findByKeyword(sessionkey).getFeatures();
+	public Room.Settings getFeatures(String sessionkey) {
+		return roomRepository.findByKeyword(sessionkey).getSettings();
 	}
 
 	@Override
 	@PreAuthorize("hasPermission(#sessionkey, 'session', 'owner')")
-	public RoomFeature updateFeatures(String sessionkey, RoomFeature features) {
+	public Room.Settings updateFeatures(String sessionkey, Room.Settings settings) {
 		final Room room = roomRepository.findByKeyword(sessionkey);
 		final UserAuthentication user = userService.getCurrentUser();
-		room.setFeatures(features);
+		room.setSettings(settings);
 		this.publisher.publishEvent(new FeatureChangeEvent(this, room));
 		roomRepository.save(room);
 
-		return room.getFeatures();
+		return room.getSettings();
 	}
 
 	@Override
@@ -573,39 +508,26 @@ public class RoomServiceImpl extends DefaultEntityServiceImpl<Room> implements R
 			feedbackService.cleanFeedbackVotesBySessionKey(sessionkey, 0);
 		}
 
-		room.setFeedbackLock(lock);
+		room.getSettings().setFeedbackLocked(lock);
 		this.publisher.publishEvent(new LockFeedbackEvent(this, room));
 		roomRepository.save(room);
 
-		return room.getFeedbackLock();
+		return room.getSettings().isFeedbackLocked();
 	}
 
 	@Override
 	@PreAuthorize("hasPermission(#sessionkey, 'session', 'owner')")
 	public boolean flipFlashcards(String sessionkey, Boolean flip) {
 		final Room room = roomRepository.findByKeyword(sessionkey);
-		final UserAuthentication user = userService.getCurrentUser();
-		room.setFlipFlashcards(flip);
 		this.publisher.publishEvent(new FlipFlashcardsEvent(this, room));
-		roomRepository.save(room);
 
-		return room.getFlipFlashcards();
+		return flip;
 	}
 
 	private void handleLogo(Room room) {
-		if (room.getPpLogo() != null) {
-			if (room.getPpLogo().startsWith("http")) {
-				final String base64ImageString = imageUtils.encodeImageToString(room.getPpLogo());
-				if (base64ImageString == null) {
-					throw new BadRequestException("Could not encode image.");
-				}
-				room.setPpLogo(base64ImageString);
-			}
-
-			// base64 adds offset to filesize, formula taken from: http://en.wikipedia.org/wiki/Base64#MIME
-			final int fileSize = (int) ((room.getPpLogo().length() - 814) / 1.37);
-			if (fileSize > uploadFileSizeByte) {
-				throw new PayloadTooLargeException("Could not save file. File is too large with " + fileSize + " Byte.");
+		if (room.getAuthor().getOrganizationLogo() != null) {
+			if (!room.getAuthor().getOrganizationLogo().startsWith("http")) {
+				throw new IllegalArgumentException("Invalid logo URL.");
 			}
 		}
 	}
diff --git a/src/main/java/de/thm/arsnova/services/TimerService.java b/src/main/java/de/thm/arsnova/services/TimerService.java
new file mode 100644
index 0000000000000000000000000000000000000000..952ba218090aebc04e27b492e3098fbb3681361c
--- /dev/null
+++ b/src/main/java/de/thm/arsnova/services/TimerService.java
@@ -0,0 +1,11 @@
+package de.thm.arsnova.services;
+
+import de.thm.arsnova.entities.UserAuthentication;
+
+public interface TimerService {
+	void startNewPiRound(final String contentId, UserAuthentication user);
+	void startNewPiRoundDelayed(final String contentId, final int time);
+	void cancelPiRoundChange(final String contentId);
+	void cancelDelayedPiRoundChange(final String contentId);
+	void resetPiRoundState(final String contentId);
+}
diff --git a/src/main/java/de/thm/arsnova/services/TimerServiceImpl.java b/src/main/java/de/thm/arsnova/services/TimerServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6c0493e8cb7276262ca8a3baccda1aba9feb721
--- /dev/null
+++ b/src/main/java/de/thm/arsnova/services/TimerServiceImpl.java
@@ -0,0 +1,169 @@
+package de.thm.arsnova.services;
+
+import de.thm.arsnova.entities.Content;
+import de.thm.arsnova.entities.Room;
+import de.thm.arsnova.entities.UserAuthentication;
+import de.thm.arsnova.events.PiRoundCancelEvent;
+import de.thm.arsnova.events.PiRoundDelayedStartEvent;
+import de.thm.arsnova.events.PiRoundEndEvent;
+import de.thm.arsnova.events.PiRoundResetEvent;
+import de.thm.arsnova.persistance.AnswerRepository;
+import de.thm.arsnova.persistance.ContentRepository;
+import de.thm.arsnova.persistance.RoomRepository;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ApplicationEventPublisherAware;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Timer;
+import java.util.TimerTask;
+
+@Service
+public class TimerServiceImpl implements TimerService, ApplicationEventPublisherAware {
+	private HashMap<String, Timer> timerList = new HashMap<>();
+	private UserService userService;
+	private RoomRepository roomRepository;
+	private ContentRepository contentRepository;
+	private AnswerRepository answerRepository;
+	private ApplicationEventPublisher publisher;
+
+	public TimerServiceImpl(final UserService userService, final RoomRepository roomRepository,
+			final ContentRepository contentRepository, final AnswerRepository answerRepository) {
+		this.userService = userService;
+		this.roomRepository = roomRepository;
+		this.contentRepository = contentRepository;
+		this.answerRepository = answerRepository;
+	}
+
+	@Override
+	@PreAuthorize("isAuthenticated() and hasPermission(#contentId, 'content', 'owner')")
+	public void startNewPiRound(final String contentId, UserAuthentication user) {
+		final Content content = contentRepository.findOne(contentId);
+		final Room room = roomRepository.findOne(content.getRoomId());
+
+		if (null == user) {
+			user = userService.getCurrentUser();
+		}
+
+		cancelDelayedPiRoundChange(contentId);
+
+		content.getState().setRoundEndTimestamp(null);
+		content.getState().setResponsesEnabled(false);
+		updateRoundManagementState(content);
+		contentRepository.save(content);
+
+		this.publisher.publishEvent(new PiRoundEndEvent(this, room, content));
+	}
+
+	@Override
+	@PreAuthorize("hasPermission(#contentId, 'content', 'owner')")
+	public void startNewPiRoundDelayed(final String contentId, final int time) {
+		final UserAuthentication user = userService.getCurrentUser();
+		final Content content = contentRepository.findOne(contentId);
+		final Room room = roomRepository.findOne(content.getRoomId());
+
+		final Date date = new Date();
+		final Timer timer = new Timer();
+		final Date endDate = new Date(date.getTime() + (time * 1000));
+		updateRoundStartVariables(content, date, endDate);
+		contentRepository.save(content);
+
+		this.publisher.publishEvent(new PiRoundDelayedStartEvent(this, room, content));
+		timerList.put(contentId, timer);
+
+		timer.schedule(new TimerTask() {
+			@Override
+			public void run() {
+				startNewPiRound(contentId, user);
+			}
+		}, endDate);
+	}
+
+	@Override
+	@PreAuthorize("hasPermission(#contentId, 'content', 'owner')")
+	public void cancelPiRoundChange(final String contentId) {
+		final Content content = contentRepository.findOne(contentId);
+		final Room room = roomRepository.findOne(content.getRoomId());
+
+		cancelDelayedPiRoundChange(contentId);
+		resetRoundManagementState(content);
+
+		if (content.getState().getRound() > 1) {
+			content.getState().setRound(content.getState().getRound() - 1);
+		}
+		content.getState().setRoundEndTimestamp(null);
+
+		contentRepository.save(content);
+		this.publisher.publishEvent(new PiRoundCancelEvent(this, room, content));
+	}
+
+	@Override
+	public void cancelDelayedPiRoundChange(final String contentId) {
+		Timer timer = timerList.get(contentId);
+
+		if (null != timer) {
+			timer.cancel();
+			timerList.remove(contentId);
+			timer.purge();
+		}
+	}
+
+	@Override
+	@PreAuthorize("hasPermission(#contentId, 'content', 'owner')")
+	@CacheEvict("answerlists")
+	public void resetPiRoundState(final String contentId) {
+		final Content content = contentRepository.findOne(contentId);
+		final Room room = roomRepository.findOne(content.getRoomId());
+		cancelDelayedPiRoundChange(contentId);
+
+		if ("freetext".equals(content.getFormat())) {
+			content.getState().setRound(0);
+		} else {
+			content.getState().setRound(1);
+		}
+
+		resetRoundManagementState(content);
+		answerRepository.deleteByContentId(content.getId());
+		contentRepository.save(content);
+		this.publisher.publishEvent(new PiRoundResetEvent(this, room, content));
+	}
+
+	private void updateRoundStartVariables(final Content content, final Date start, final Date end) {
+		if (content.getState().getRound() == 1 && content.getState().getRoundEndTimestamp() == null) {
+			content.getState().setRound(2);
+		}
+
+		content.getState().setVisible(true);
+		content.getState().setSolutionVisible(false);
+		content.getState().setResponsesVisible(false);
+		content.getState().setResponsesEnabled(true);
+		content.getState().setRoundEndTimestamp(end);
+	}
+
+	private void updateRoundManagementState(final Content content) {
+		if (content.getState().getRoundEndTimestamp() != null && new Date().compareTo(content.getState().getRoundEndTimestamp()) > 0) {
+			content.getState().setRoundEndTimestamp(null);
+		}
+	}
+
+	private void resetRoundManagementState(final Content content) {
+		content.getState().setSolutionVisible(false);
+		content.getState().setResponsesVisible(false);
+		content.getState().setResponsesEnabled(false);
+		content.getState().setRoundEndTimestamp(null);
+	}
+
+	private void resetQuestionState(final Content content) {
+		content.getState().setResponsesEnabled(true);
+		content.getState().setRound(1);
+		content.getState().setRoundEndTimestamp(null);
+	}
+
+	@Override
+	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
+		this.publisher = applicationEventPublisher;
+	}
+}
diff --git a/src/main/java/de/thm/arsnova/services/UserService.java b/src/main/java/de/thm/arsnova/services/UserService.java
index fb22c5a17a2c32f3a913e877f79168e2fe52a581..de0cfdc0362983c210308b7c5615f056b5675c48 100644
--- a/src/main/java/de/thm/arsnova/services/UserService.java
+++ b/src/main/java/de/thm/arsnova/services/UserService.java
@@ -18,7 +18,7 @@
 package de.thm.arsnova.services;
 
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.DbUser;
+import de.thm.arsnova.entities.UserProfile;
 
 import java.util.Map;
 import java.util.Set;
@@ -58,15 +58,15 @@ public interface UserService {
 
 	int loggedInUsers();
 
-	DbUser getByUsername(String username);
+	UserProfile getByUsername(String username);
 
-	DbUser create(String username, String password);
+	UserProfile create(String username, String password);
 
-	DbUser update(DbUser dbUser);
+	UserProfile update(UserProfile userProfile);
 
-	DbUser deleteByUsername(String username);
+	UserProfile deleteByUsername(String username);
 
 	void initiatePasswordReset(String username);
 
-	boolean resetPassword(DbUser dbUser, String key, String password);
+	boolean resetPassword(UserProfile userProfile, String key, String password);
 }
diff --git a/src/main/java/de/thm/arsnova/services/UserServiceImpl.java b/src/main/java/de/thm/arsnova/services/UserServiceImpl.java
index e3a07db1a1bb81d2c32f6f197d50759c5b500e46..0e97b924f791e7f5fc246db95cd8f18d332f75e9 100644
--- a/src/main/java/de/thm/arsnova/services/UserServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/UserServiceImpl.java
@@ -19,7 +19,7 @@ package de.thm.arsnova.services;
 
 import com.codahale.metrics.annotation.Gauge;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.DbUser;
+import de.thm.arsnova.entities.UserProfile;
 import de.thm.arsnova.exceptions.BadRequestException;
 import de.thm.arsnova.exceptions.NotFoundException;
 import de.thm.arsnova.exceptions.UnauthorizedException;
@@ -60,6 +60,7 @@ import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -345,12 +346,12 @@ public class UserServiceImpl implements UserService {
 	}
 
 	@Override
-	public DbUser getByUsername(String username) {
+	public UserProfile getByUsername(String username) {
 		return userRepository.findByUsername(username.toLowerCase());
 	}
 
 	@Override
-	public DbUser create(String username, String password) {
+	public UserProfile create(String username, String password) {
 		String lcUsername = username.toLowerCase();
 
 		if (null == keygen) {
@@ -373,13 +374,15 @@ public class UserServiceImpl implements UserService {
 			return null;
 		}
 
-		DbUser dbUser = new DbUser();
-		dbUser.setUsername(lcUsername);
-		dbUser.setPassword(encodePassword(password));
-		dbUser.setActivationKey(RandomStringUtils.randomAlphanumeric(32));
-		dbUser.setCreation(System.currentTimeMillis());
+		UserProfile userProfile = new UserProfile();
+		UserProfile.Account account = userProfile.new Account();
+		userProfile.setAccount(account);
+		userProfile.setLoginId(lcUsername);
+		account.setPassword(encodePassword(password));
+		account.setActivationKey(RandomStringUtils.randomAlphanumeric(32));
+		userProfile.setCreationTimestamp(new Date());
 
-		DbUser result = userRepository.save(dbUser);
+		UserProfile result = userRepository.save(userProfile);
 		if (null != result) {
 			sendActivationEmail(result);
 		} else {
@@ -397,7 +400,7 @@ public class UserServiceImpl implements UserService {
 		return encoder.encode(password);
 	}
 
-	private void sendActivationEmail(DbUser dbUser) {
+	private void sendActivationEmail(UserProfile userProfile) {
 		String activationUrl;
 		try {
 			activationUrl = MessageFormat.format(
@@ -405,8 +408,8 @@ public class UserServiceImpl implements UserService {
 				rootUrl,
 				customizationPath,
 				activationPath,
-				UriUtils.encodeQueryParam(dbUser.getUsername(), "UTF-8"),
-				dbUser.getActivationKey()
+				UriUtils.encodeQueryParam(userProfile.getLoginId(), "UTF-8"),
+				userProfile.getAccount().getActivationKey()
 			);
 		} catch (UnsupportedEncodingException e) {
 			logger.error("Sending of activation mail failed.", e);
@@ -414,7 +417,7 @@ public class UserServiceImpl implements UserService {
 			return;
 		}
 
-		sendEmail(dbUser, regMailSubject, MessageFormat.format(regMailBody, activationUrl));
+		sendEmail(userProfile, regMailSubject, MessageFormat.format(regMailBody, activationUrl));
 	}
 
 	private void parseMailAddressPattern() {
@@ -441,16 +444,16 @@ public class UserServiceImpl implements UserService {
 	}
 
 	@Override
-	public DbUser update(DbUser dbUser) {
-		if (null != dbUser.getId()) {
-			return userRepository.save(dbUser);
+	public UserProfile update(UserProfile userProfile) {
+		if (null != userProfile.getId()) {
+			return userRepository.save(userProfile);
 		}
 
 		return null;
 	}
 
 	@Override
-	public DbUser deleteByUsername(String username) {
+	public UserProfile deleteByUsername(String username) {
 		UserAuthentication user = getCurrentUser();
 		if (!user.getUsername().equals(username.toLowerCase())
 				&& !SecurityContextHolder.getContext().getAuthentication().getAuthorities()
@@ -458,34 +461,35 @@ public class UserServiceImpl implements UserService {
 			throw new UnauthorizedException();
 		}
 
-		DbUser dbUser = getByUsername(username);
-		if (null == dbUser) {
+		UserProfile userProfile = getByUsername(username);
+		if (null == userProfile) {
 			throw new NotFoundException();
 		}
 
-		userRepository.delete(dbUser);
+		userRepository.delete(userProfile);
 
-		return dbUser;
+		return userProfile;
 	}
 
 	@Override
 	public void initiatePasswordReset(String username) {
-		DbUser dbUser = getByUsername(username);
-		if (null == dbUser) {
+		UserProfile userProfile = getByUsername(username);
+		if (null == userProfile) {
 			logger.info("Password reset failed. User {} does not exist.", username);
 
 			throw new NotFoundException();
 		}
-		if (System.currentTimeMillis() < dbUser.getPasswordResetTime() + REPEATED_PASSWORD_RESET_DELAY_MS) {
+		UserProfile.Account account = userProfile.getAccount();
+		if (System.currentTimeMillis() < account.getPasswordResetTime().getTime() + REPEATED_PASSWORD_RESET_DELAY_MS) {
 			logger.info("Password reset failed. The reset delay for User {} is still active.", username);
 
 			throw new BadRequestException();
 		}
 
-		dbUser.setPasswordResetKey(RandomStringUtils.randomAlphanumeric(32));
-		dbUser.setPasswordResetTime(System.currentTimeMillis());
+		account.setPasswordResetKey(RandomStringUtils.randomAlphanumeric(32));
+		account.setPasswordResetTime(new Date());
 
-		if (null == userRepository.save(dbUser)) {
+		if (null == userRepository.save(userProfile)) {
 			logger.error("Password reset failed. {} could not be updated.", username);
 		}
 
@@ -496,8 +500,8 @@ public class UserServiceImpl implements UserService {
 				rootUrl,
 				customizationPath,
 				resetPasswordPath,
-				UriUtils.encodeQueryParam(dbUser.getUsername(), "UTF-8"),
-				dbUser.getPasswordResetKey()
+				UriUtils.encodeQueryParam(userProfile.getLoginId(), "UTF-8"),
+					account.getPasswordResetKey()
 			);
 		} catch (UnsupportedEncodingException e) {
 			logger.error("Sending of password reset mail failed.", e);
@@ -505,45 +509,46 @@ public class UserServiceImpl implements UserService {
 			return;
 		}
 
-		sendEmail(dbUser, resetPasswordMailSubject, MessageFormat.format(resetPasswordMailBody, resetPasswordUrl));
+		sendEmail(userProfile, resetPasswordMailSubject, MessageFormat.format(resetPasswordMailBody, resetPasswordUrl));
 	}
 
 	@Override
-	public boolean resetPassword(DbUser dbUser, String key, String password) {
-		if (null == key || "".equals(key) || !key.equals(dbUser.getPasswordResetKey())) {
-			logger.info("Password reset failed. Invalid key provided for User {}.", dbUser.getUsername());
+	public boolean resetPassword(UserProfile userProfile, String key, String password) {
+		UserProfile.Account account = userProfile.getAccount();
+		if (null == key || "".equals(key) || !key.equals(account.getPasswordResetKey())) {
+			logger.info("Password reset failed. Invalid key provided for User {}.", userProfile.getLoginId());
 
 			return false;
 		}
-		if (System.currentTimeMillis() > dbUser.getPasswordResetTime() + PASSWORD_RESET_KEY_DURABILITY_MS) {
-			logger.info("Password reset failed. Key provided for User {} is no longer valid.", dbUser.getUsername());
+		if (System.currentTimeMillis() > account.getPasswordResetTime().getTime() + PASSWORD_RESET_KEY_DURABILITY_MS) {
+			logger.info("Password reset failed. Key provided for User {} is no longer valid.", userProfile.getLoginId());
 
-			dbUser.setPasswordResetKey(null);
-			dbUser.setPasswordResetTime(0);
-			update(dbUser);
+			account.setPasswordResetKey(null);
+			account.setPasswordResetTime(new Date(0));
+			update(userProfile);
 
 			return false;
 		}
 
-		dbUser.setPassword(encodePassword(password));
-		dbUser.setPasswordResetKey(null);
-		if (null == update(dbUser)) {
-			logger.error("Password reset failed. {} could not be updated.", dbUser.getUsername());
+		account.setPassword(encodePassword(password));
+		account.setPasswordResetKey(null);
+		if (null == update(userProfile)) {
+			logger.error("Password reset failed. {} could not be updated.", userProfile.getLoginId());
 		}
 
 		return true;
 	}
 
-	private void sendEmail(DbUser dbUser, String subject, String body) {
+	private void sendEmail(UserProfile userProfile, String subject, String body) {
 		MimeMessage msg = mailSender.createMimeMessage();
 		MimeMessageHelper helper = new MimeMessageHelper(msg, "UTF-8");
 		try {
 			helper.setFrom(mailSenderName + "<" + mailSenderAddress + ">");
-			helper.setTo(dbUser.getUsername());
+			helper.setTo(userProfile.getLoginId());
 			helper.setSubject(subject);
 			helper.setText(body);
 
-			logger.info("Sending mail \"{}\" from \"{}\" to \"{}\"", subject, msg.getFrom(), dbUser.getUsername());
+			logger.info("Sending mail \"{}\" from \"{}\" to \"{}\"", subject, msg.getFrom(), userProfile.getLoginId());
 			mailSender.send(msg);
 		} catch (MailException | MessagingException e) {
 			logger.warn("Mail \"{}\" could not be sent.", subject, e);
diff --git a/src/main/java/de/thm/arsnova/services/score/ScoreCalculator.java b/src/main/java/de/thm/arsnova/services/score/ScoreCalculator.java
index 09560574ffa60c5a23a2960baeeed11c5cd946de..73cf7b31e31d799ab864d06d9dadace0616e1b9a 100644
--- a/src/main/java/de/thm/arsnova/services/score/ScoreCalculator.java
+++ b/src/main/java/de/thm/arsnova/services/score/ScoreCalculator.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.services.score;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.UserAuthentication;
 import de.thm.arsnova.entities.transport.ScoreStatistics;
 
diff --git a/src/main/java/de/thm/arsnova/services/score/VariantScoreCalculator.java b/src/main/java/de/thm/arsnova/services/score/VariantScoreCalculator.java
index bbe619e63d5422b498ef969b23f6170e45c05294..770238ae8f2e016c9013130b334f5ff1cd4f0406 100644
--- a/src/main/java/de/thm/arsnova/services/score/VariantScoreCalculator.java
+++ b/src/main/java/de/thm/arsnova/services/score/VariantScoreCalculator.java
@@ -17,7 +17,7 @@
  */
 package de.thm.arsnova.services.score;
 
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.entities.UserAuthentication;
 import de.thm.arsnova.entities.transport.ScoreStatistics;
 import de.thm.arsnova.persistance.SessionStatisticsRepository;
diff --git a/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java b/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java
index acec042ab3d9e79596375a0f0b9160d5f8d48474..f8d997077f046e5a171dacdf25291dae8391644b 100644
--- a/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java
+++ b/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java
@@ -29,9 +29,8 @@ import com.corundumstudio.socketio.listener.DisconnectListener;
 import com.corundumstudio.socketio.protocol.Packet;
 import com.corundumstudio.socketio.protocol.PacketType;
 import de.thm.arsnova.entities.UserAuthentication;
-import de.thm.arsnova.entities.migration.v2.Comment;
+import de.thm.arsnova.entities.Comment;
 import de.thm.arsnova.entities.ScoreOptions;
-import de.thm.arsnova.entities.migration.v2.RoomFeature;
 import de.thm.arsnova.events.*;
 import de.thm.arsnova.exceptions.NoContentException;
 import de.thm.arsnova.exceptions.NotFoundException;
@@ -150,9 +149,9 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 					return;
 				}
 				final String sessionKey = userService.getSessionByUsername(u.getUsername());
-				final de.thm.arsnova.entities.migration.v2.Room room = roomService.getInternal(sessionKey, u);
+				final de.thm.arsnova.entities.Room room = roomService.getInternal(sessionKey, u);
 
-				if (room.getFeedbackLock()) {
+				if (room.getSettings().isFeedbackLocked()) {
 					logger.debug("Feedback save blocked: {}", u, sessionKey, data.getValue());
 				} else {
 					logger.debug("Feedback recieved: {}", u, sessionKey, data.getValue());
@@ -229,14 +228,15 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 			@Override
 			@Timed(name = "setLearningProgressOptionsEvent.onData")
 			public void onData(SocketIOClient client, ScoreOptions scoreOptions, AckRequest ack) {
-				final UserAuthentication user = userService.getUser2SocketId(client.getSessionId());
-				final String sessionKey = userService.getSessionByUsername(user.getUsername());
-				final de.thm.arsnova.entities.migration.v2.Room room = roomService.getInternal(sessionKey, user);
-				if (room.isCreator(user)) {
-					room.setLearningProgressOptions(scoreOptions);
-					roomService.updateInternal(room, user);
-					broadcastInSession(room.getKeyword(), "learningProgressOptions", scoreOptions);
-				}
+				throw new UnsupportedOperationException("Not implemented.");
+//				final UserAuthentication user = userService.getUser2SocketId(client.getSessionId());
+//				final String sessionKey = userService.getSessionByUsername(user.getUsername());
+//				final de.thm.arsnova.entities.Room room = roomService.getInternal(sessionKey, user);
+//				if (room.getOwnerId().equals(user.getId())) {
+//					room.setLearningProgressOptions(scoreOptions);
+//					roomService.updateInternal(room, user);
+//					broadcastInSession(room.getShortId(), "learningProgressOptions", scoreOptions);
+//				}
 			}
 		});
 
@@ -335,10 +335,10 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 		this.useSSL = useSSL;
 	}
 
-	public void reportDeletedFeedback(final UserAuthentication user, final Set<de.thm.arsnova.entities.migration.v2.Room> arsRooms) {
+	public void reportDeletedFeedback(final UserAuthentication user, final Set<de.thm.arsnova.entities.Room> arsRooms) {
 		final List<String> keywords = new ArrayList<>();
-		for (final de.thm.arsnova.entities.migration.v2.Room room : arsRooms) {
-			keywords.add(room.getKeyword());
+		for (final de.thm.arsnova.entities.Room room : arsRooms) {
+			keywords.add(room.getShortId());
 		}
 		this.sendToUser(user, "feedbackReset", keywords);
 	}
@@ -372,21 +372,21 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 	 * relevant Socket.IO data, the client needs to know after joining a session.
 	 */
 	public void reportSessionDataToClient(final String sessionKey, final UserAuthentication user, final SocketIOClient client) {
-		final de.thm.arsnova.entities.migration.v2.Room room = roomService.getInternal(sessionKey, user);
-		final RoomFeature features = roomService.getFeatures(sessionKey);
+		final de.thm.arsnova.entities.Room room = roomService.getInternal(sessionKey, user);
+		final de.thm.arsnova.entities.Room.Settings settings = roomService.getFeatures(sessionKey);
 
 		client.sendEvent("unansweredLecturerQuestions", contentService.getUnAnsweredLectureQuestionIds(sessionKey, user));
 		client.sendEvent("unansweredPreparationQuestions", contentService.getUnAnsweredPreparationQuestionIds(sessionKey, user));
 		client.sendEvent("countLectureQuestionAnswers", contentService.countLectureQuestionAnswersInternal(sessionKey));
 		client.sendEvent("countPreparationQuestionAnswers", contentService.countPreparationQuestionAnswersInternal(sessionKey));
 		client.sendEvent("activeUserCountData", roomService.activeUsers(sessionKey));
-		client.sendEvent("learningProgressOptions", room.getLearningProgressOptions());
+//		client.sendEvent("learningProgressOptions", room.getLearningProgressOptions());
 		final de.thm.arsnova.entities.Feedback fb = feedbackService.getBySessionKey(sessionKey);
 		client.sendEvent("feedbackData", fb.getValues());
 
-		if (features.isFlashcard() || features.isFlashcardFeature()) {
+		if (settings.isFlashcardsEnabled()) {
 			client.sendEvent("countFlashcards", contentService.countFlashcardsForUserInternal(sessionKey));
-			client.sendEvent("flipFlashcards", room.getFlipFlashcards());
+//			client.sendEvent("flipFlashcards", room.getFlipFlashcards());
 		}
 
 		try {
@@ -398,18 +398,18 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 		}
 	}
 
-	public void reportUpdatedFeedbackForSession(final de.thm.arsnova.entities.migration.v2.Room room) {
-		final de.thm.arsnova.entities.Feedback fb = feedbackService.getBySessionKey(room.getKeyword());
-		broadcastInSession(room.getKeyword(), "feedbackData", fb.getValues());
+	public void reportUpdatedFeedbackForSession(final de.thm.arsnova.entities.Room room) {
+		final de.thm.arsnova.entities.Feedback fb = feedbackService.getBySessionKey(room.getShortId());
+		broadcastInSession(room.getShortId(), "feedbackData", fb.getValues());
 		try {
-			final long averageFeedback = feedbackService.calculateRoundedAverageFeedback(room.getKeyword());
-			broadcastInSession(room.getKeyword(), "feedbackDataRoundedAverage", averageFeedback);
+			final long averageFeedback = feedbackService.calculateRoundedAverageFeedback(room.getShortId());
+			broadcastInSession(room.getShortId(), "feedbackDataRoundedAverage", averageFeedback);
 		} catch (final NoContentException e) {
-			broadcastInSession(room.getKeyword(), "feedbackDataRoundedAverage", null);
+			broadcastInSession(room.getShortId(), "feedbackDataRoundedAverage", null);
 		}
 	}
 
-	public void reportFeedbackForUserInSession(final de.thm.arsnova.entities.migration.v2.Room room, final UserAuthentication user) {
+	public void reportFeedbackForUserInSession(final Room room, final UserAuthentication user) {
 		final de.thm.arsnova.entities.Feedback fb = feedbackService.getBySessionKey(room.getKeyword());
 		Long averageFeedback;
 		try {
@@ -436,34 +436,34 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 		broadcastInSession(sessionKey, "activeUserCountData", count);
 	}
 
-	public void reportAnswersToLecturerQuestionAvailable(final de.thm.arsnova.entities.migration.v2.Room room, final Content content) {
-		broadcastInSession(room.getKeyword(), "answersToLecQuestionAvail", content.get_id());
+	public void reportAnswersToLecturerQuestionAvailable(final de.thm.arsnova.entities.Room room, final Content content) {
+		broadcastInSession(room.getShortId(), "answersToLecQuestionAvail", content.get_id());
 	}
 
-	public void reportAudienceQuestionAvailable(final de.thm.arsnova.entities.migration.v2.Room room, final Comment audienceQuestion) {
+	public void reportAudienceQuestionAvailable(final de.thm.arsnova.entities.Room room, final Comment audienceQuestion) {
 		/* TODO role handling implementation, send this only to users with role lecturer */
-		broadcastInSession(room.getKeyword(), "audQuestionAvail", audienceQuestion.getId());
+		broadcastInSession(room.getShortId(), "audQuestionAvail", audienceQuestion.getId());
 	}
 
-	public void reportLecturerQuestionAvailable(final de.thm.arsnova.entities.migration.v2.Room room, final List<de.thm.arsnova.entities.migration.v2.Content> qs) {
+	public void reportLecturerQuestionAvailable(final de.thm.arsnova.entities.Room room, final List<de.thm.arsnova.entities.Content> qs) {
 		List<Content> contents = new ArrayList<>();
-		for (de.thm.arsnova.entities.migration.v2.Content q : qs) {
+		for (de.thm.arsnova.entities.Content q : qs) {
 			contents.add(new Content(q));
 		}
 
 		/* TODO role handling implementation, send this only to users with role audience */
 		if (!qs.isEmpty()) {
-			broadcastInSession(room.getKeyword(), "lecQuestionAvail", contents.get(0).get_id()); // deprecated!
+			broadcastInSession(room.getShortId(), "lecQuestionAvail", contents.get(0).get_id()); // deprecated!
 		}
-		broadcastInSession(room.getKeyword(), "lecturerQuestionAvailable", contents);
+		broadcastInSession(room.getShortId(), "lecturerQuestionAvailable", contents);
 	}
 
-	public void reportLecturerQuestionsLocked(final de.thm.arsnova.entities.migration.v2.Room room, final List<de.thm.arsnova.entities.migration.v2.Content> qs) {
+	public void reportLecturerQuestionsLocked(final de.thm.arsnova.entities.Room room, final List<de.thm.arsnova.entities.Content> qs) {
 		List<Content> contents = new ArrayList<>();
-		for (de.thm.arsnova.entities.migration.v2.Content q : qs) {
+		for (de.thm.arsnova.entities.Content q : qs) {
 			contents.add(new Content(q));
 		}
-		broadcastInSession(room.getKeyword(), "lecturerQuestionLocked", contents);
+		broadcastInSession(room.getShortId(), "lecturerQuestionLocked", contents);
 	}
 
 	public void reportSessionStatus(final String sessionKey, final boolean active) {
@@ -519,17 +519,17 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 	@Override
 	@Timed(name = "visit.NewAnswerEvent")
 	public void visit(NewAnswerEvent event) {
-		final String sessionKey = event.getRoom().getKeyword();
+		final String sessionKey = event.getRoom().getShortId();
 		this.reportAnswersToLecturerQuestionAvailable(event.getRoom(), new Content(event.getContent()));
 		broadcastInSession(sessionKey, "countQuestionAnswersByQuestionId", contentService.countAnswersAndAbstentionsInternal(event.getContent().getId()));
 		broadcastInSession(sessionKey, "countLectureQuestionAnswers", contentService.countLectureQuestionAnswersInternal(sessionKey));
 		broadcastInSession(sessionKey, "countPreparationQuestionAnswers", contentService.countPreparationQuestionAnswersInternal(sessionKey));
 
 		// Update the unanswered count for the content variant that was answered.
-		final de.thm.arsnova.entities.migration.v2.Content content = event.getContent();
-		if ("lecture".equals(content.getQuestionVariant())) {
+		final de.thm.arsnova.entities.Content content = event.getContent();
+		if ("lecture".equals(content.getGroup())) {
 			sendToUser(event.getUser(), "unansweredLecturerQuestions", contentService.getUnAnsweredLectureQuestionIds(sessionKey, event.getUser()));
-		} else if ("preparation".equals(content.getQuestionVariant())) {
+		} else if ("preparation".equals(content.getGroup())) {
 			sendToUser(event.getUser(), "unansweredPreparationQuestions", contentService.getUnAnsweredPreparationQuestionIds(sessionKey, event.getUser()));
 		}
 	}
@@ -538,7 +538,7 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 	@Override
 	@Timed(name = "visit.DeleteAnswerEvent")
 	public void visit(DeleteAnswerEvent event) {
-		final String sessionKey = event.getRoom().getKeyword();
+		final String sessionKey = event.getRoom().getShortId();
 		this.reportAnswersToLecturerQuestionAvailable(event.getRoom(), new Content(event.getQuestion()));
 		// We do not know which user's answer was deleted, so we can't update his 'unanswered' list of questions...
 		broadcastInSession(sessionKey, "countLectureQuestionAnswers", contentService.countLectureQuestionAnswersInternal(sessionKey));
@@ -549,7 +549,7 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 	@Override
 	@Timed(name = "visit.PiRoundDelayedStartEvent")
 	public void visit(PiRoundDelayedStartEvent event) {
-		final String sessionKey = event.getRoom().getKeyword();
+		final String sessionKey = event.getRoom().getShortId();
 		broadcastInSession(sessionKey, "startDelayedPiRound", event.getPiRoundInformations());
 	}
 
@@ -557,7 +557,7 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 	@Override
 	@Timed(name = "visit.PiRoundEndEvent")
 	public void visit(PiRoundEndEvent event) {
-		final String sessionKey = event.getRoom().getKeyword();
+		final String sessionKey = event.getRoom().getShortId();
 		broadcastInSession(sessionKey, "endPiRound", event.getPiRoundEndInformations());
 	}
 
@@ -565,66 +565,66 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 	@Override
 	@Timed(name = "visit.PiRoundCancelEvent")
 	public void visit(PiRoundCancelEvent event) {
-		final String sessionKey = event.getRoom().getKeyword();
-		broadcastInSession(sessionKey, "cancelPiRound", event.getQuestionId());
+		final String sessionKey = event.getRoom().getShortId();
+		broadcastInSession(sessionKey, "cancelPiRound", event.getContentId());
 	}
 
 	@Override
 	public void visit(PiRoundResetEvent event) {
-		final String sessionKey = event.getRoom().getKeyword();
+		final String sessionKey = event.getRoom().getShortId();
 		broadcastInSession(sessionKey, "resetPiRound", event.getPiRoundResetInformations());
 	}
 
 	@Override
 	public void visit(LockVoteEvent event) {
-		final String sessionKey = event.getRoom().getKeyword();
+		final String sessionKey = event.getRoom().getShortId();
 		broadcastInSession(sessionKey, "lockVote", event.getVotingAdmission());
 	}
 
 	@Override
 	public void visit(UnlockVoteEvent event) {
-		final String sessionKey = event.getRoom().getKeyword();
+		final String sessionKey = event.getRoom().getShortId();
 		broadcastInSession(sessionKey, "unlockVote", event.getVotingAdmission());
 	}
 
 	@Override
 	public void visit(LockVotesEvent event) {
 		List<Content> contents = new ArrayList<>();
-		for (de.thm.arsnova.entities.migration.v2.Content q : event.getQuestions()) {
+		for (de.thm.arsnova.entities.Content q : event.getQuestions()) {
 			contents.add(new Content(q));
 		}
-		broadcastInSession(event.getRoom().getKeyword(), "lockVotes", contents);
+		broadcastInSession(event.getRoom().getShortId(), "lockVotes", contents);
 	}
 
 	@Override
 	public void visit(UnlockVotesEvent event) {
 		List<Content> contents = new ArrayList<>();
-		for (de.thm.arsnova.entities.migration.v2.Content q : event.getQuestions()) {
+		for (de.thm.arsnova.entities.Content q : event.getQuestions()) {
 			contents.add(new Content(q));
 		}
-		broadcastInSession(event.getRoom().getKeyword(), "unlockVotes", contents);
+		broadcastInSession(event.getRoom().getShortId(), "unlockVotes", contents);
 	}
 
 	@Override
 	public void visit(FeatureChangeEvent event) {
-		final String sessionKey = event.getRoom().getKeyword();
-		final RoomFeature features = event.getRoom().getFeatures();
-		broadcastInSession(sessionKey, "featureChange", features);
+		final String sessionKey = event.getRoom().getShortId();
+		final de.thm.arsnova.entities.Room.Settings settings = event.getRoom().getSettings();
+		broadcastInSession(sessionKey, "featureChange", settings);
 
-		if (features.isFlashcard() || features.isFlashcardFeature()) {
+		if (settings.isFlashcardsEnabled()) {
 			broadcastInSession(sessionKey, "countFlashcards", contentService.countFlashcardsForUserInternal(sessionKey));
-			broadcastInSession(sessionKey, "flipFlashcards", event.getRoom().getFlipFlashcards());
+//			broadcastInSession(sessionKey, "flipFlashcards", event.getRoom().getFlipFlashcards());
 		}
 	}
 
 	@Override
 	public void visit(LockFeedbackEvent event) {
-		broadcastInSession(event.getRoom().getKeyword(), "lockFeedback", event.getRoom().getFeedbackLock());
+		broadcastInSession(event.getRoom().getShortId(), "lockFeedback", event.getRoom().getSettings().isFeedbackLocked());
 	}
 
 	@Override
 	public void visit(FlipFlashcardsEvent event) {
-		broadcastInSession(event.getRoom().getKeyword(), "flipFlashcards", event.getRoom().getFlipFlashcards());
+//		broadcastInSession(event.getRoom().getShortId(), "flipFlashcards", event.getRoom().getFlipFlashcards());
 	}
 
 	@Override
@@ -676,12 +676,12 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova
 
 	@Override
 	public void visit(StatusRoomEvent event) {
-		this.reportSessionStatus(event.getRoom().getKeyword(), event.getRoom().isActive());
+		this.reportSessionStatus(event.getRoom().getShortId(), !event.getRoom().isClosed());
 	}
 
 	@Override
 	public void visit(ChangeScoreEvent event) {
-		broadcastInSession(event.getRoom().getKeyword(), "learningProgressChange", null);
+		broadcastInSession(event.getRoom().getShortId(), "learningProgressChange", null);
 	}
 
 	@Override
diff --git a/src/main/java/de/thm/arsnova/websocket/message/Content.java b/src/main/java/de/thm/arsnova/websocket/message/Content.java
index 6a2ec724e1dddfa345274b7dbd57c7feac54cd66..ffd294c2977624376664fae840ad6e7c49e1edce 100644
--- a/src/main/java/de/thm/arsnova/websocket/message/Content.java
+++ b/src/main/java/de/thm/arsnova/websocket/message/Content.java
@@ -25,9 +25,9 @@ public class Content {
 	private final String _id;
 	private final String variant;
 
-	public Content(de.thm.arsnova.entities.migration.v2.Content content) {
+	public Content(de.thm.arsnova.entities.Content content) {
 		this._id = content.getId();
-		this.variant = content.getQuestionVariant();
+		this.variant = content.getGroup();
 	}
 
 	public String get_id() {
diff --git a/src/test/java/de/thm/arsnova/services/DefaultEntityServiceImplTest.java b/src/test/java/de/thm/arsnova/services/DefaultEntityServiceImplTest.java
index 41fc67bf7bda5f37fc649b01097a172074043de1..169cad16dd515f2ea085bc24f460f7f6fbc3232c 100644
--- a/src/test/java/de/thm/arsnova/services/DefaultEntityServiceImplTest.java
+++ b/src/test/java/de/thm/arsnova/services/DefaultEntityServiceImplTest.java
@@ -5,7 +5,7 @@ import de.thm.arsnova.config.AppConfig;
 import de.thm.arsnova.config.TestAppConfig;
 import de.thm.arsnova.config.TestPersistanceConfig;
 import de.thm.arsnova.config.TestSecurityConfig;
-import de.thm.arsnova.entities.migration.v2.Room;
+import de.thm.arsnova.entities.Room;
 import de.thm.arsnova.persistance.RoomRepository;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -51,27 +51,27 @@ public class DefaultEntityServiceImplTest {
 
 		final String originalId = "d8833f0d78964a9487ded02ba2dfbbad";
 		final String originalName = "Test Room";
-		final String originalCreator = "TestUser";
-		final boolean originalActive = false;
+		final String originalOwnerId = "TestUser";
+		final boolean originalActive = true;
 		final Room room = new Room();
 		room.setId(originalId);
 		room.setName(originalName);
-		room.setActive(originalActive);
-		room.setCreator(originalCreator);
+		room.setClosed(originalActive);
+		room.setOwnerId(originalOwnerId);
 
 		final String patchedName = "Patched Room";
-		final boolean patchedActive = true;
+		final boolean patchedActive = false;
 		final Map<String, Object> patchedValues = new HashMap<>();
 		patchedValues.put("name", patchedName);
-		patchedValues.put("active", patchedActive);
-		patchedValues.put("creator", "Should not be changeable.");
+		patchedValues.put("closed", patchedActive);
+		patchedValues.put("ownerId", "Should not be changeable.");
 
 		entityService.patch(room, patchedValues);
 
 		assertEquals(originalId, room.getId());
 		assertEquals(patchedName, room.getName());
-		assertEquals(patchedActive, room.isActive());
-		assertEquals(originalCreator, room.getCreator());
+		assertEquals(patchedActive, room.isClosed());
+		assertEquals(originalOwnerId, room.getOwnerId());
 	}
 
 	@Test
@@ -85,41 +85,41 @@ public class DefaultEntityServiceImplTest {
 		List<Room> sessions = new ArrayList<>();
 		final String originalId1 = "d8833f0d78964a9487ded02ba2dfbbad";
 		final String originalName1 = "Test Room 1";
-		final String originalCreator1 = "TestUser";
-		final boolean originalActive1 = false;
+		final String originalOwnerId1 = "TestUser";
+		final boolean originalClosed1 = true;
 		final Room room1 = new Room();
 		room1.setId(originalId1);
 		room1.setName(originalName1);
-		room1.setActive(originalActive1);
-		room1.setCreator(originalCreator1);
+		room1.setClosed(originalClosed1);
+		room1.setOwnerId(originalOwnerId1);
 		sessions.add(room1);
 		final String originalId2 = "3dc8cbff05da49d5980f6c001a6ea867";
 		final String originalName2 = "Test Room 2";
-		final String originalCreator2 = "TestUser";
-		final boolean originalActive2 = false;
+		final String originalOwnerId2 = "TestUser";
+		final boolean originalClosed2 = true;
 		final Room room2 = new Room();
 		room2.setId(originalId2);
 		room2.setName(originalName2);
-		room2.setActive(originalActive2);
-		room2.setCreator(originalCreator2);
+		room2.setClosed(originalClosed2);
+		room2.setOwnerId(originalOwnerId2);
 		sessions.add(room2);
 
 		final String patchedName = "Patched Room";
-		final boolean patchedActive = true;
+		final boolean patchedClosed = false;
 		final Map<String, Object> patchedValues = new HashMap<>();
 		patchedValues.put("name", patchedName);
-		patchedValues.put("active", patchedActive);
-		patchedValues.put("creator", "Should not be changeable.");
+		patchedValues.put("closed", patchedClosed);
+		patchedValues.put("ownerId", "Should not be changeable.");
 
 		entityService.patch(sessions, patchedValues);
 
 		assertEquals(originalId1, room1.getId());
 		assertEquals(patchedName, room1.getName());
-		assertEquals(patchedActive, room1.isActive());
-		assertEquals(originalCreator1, room1.getCreator());
+		assertEquals(patchedClosed, room1.isClosed());
+		assertEquals(originalOwnerId1, room1.getOwnerId());
 		assertEquals(originalId2, room2.getId());
 		assertEquals(patchedName, room2.getName());
-		assertEquals(patchedActive, room2.isActive());
-		assertEquals(originalCreator2, room2.getCreator());
+		assertEquals(patchedClosed, room2.isClosed());
+		assertEquals(originalOwnerId2, room2.getOwnerId());
 	}
 }