diff --git a/src/main/java/de/bps/onyx/plugin/wsserver/ReturnWSService.java b/src/main/java/de/bps/onyx/plugin/wsserver/ReturnWSService.java
index 18d8cf4390544951e7c0cd0ef41bb76c7a2800a2..10f9e672195c1a6ea5be4667692e3835bdd371c2 100644
--- a/src/main/java/de/bps/onyx/plugin/wsserver/ReturnWSService.java
+++ b/src/main/java/de/bps/onyx/plugin/wsserver/ReturnWSService.java
@@ -41,9 +41,9 @@ import org.olat.core.util.FileUtils;
 import org.olat.core.util.WebappHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
-import org.olat.course.assessment.NewCachePersistingAssessmentManager;
+import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.manager.CourseAssessmentManagerImpl;
 import org.olat.course.nodes.CourseNode;
-import org.olat.course.properties.CoursePropertyManager;
 import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.course.run.userview.UserCourseEnvironmentImpl;
@@ -204,9 +204,8 @@ public class ReturnWSService {
 								ICourse course = CourseFactory.loadCourse(resourceId);
 
 								CourseNode courseNode = course.getRunStructure().getNode(qtiResultSet.getOlatResourceDetail());
-								NewCachePersistingAssessmentManager am = (NewCachePersistingAssessmentManager) NewCachePersistingAssessmentManager.getInstance(course);
+								AssessmentManager am = new CourseAssessmentManagerImpl(course.getCourseEnvironment().getCourseGroupManager().getCourseEntry());
 
-								CoursePropertyManager cpm = course.getCourseEnvironment().getCoursePropertyManager();
 								// create an identenv with no roles, no
 								// attributes, no locale
 								IdentityEnvironment ienv = new IdentityEnvironment();
@@ -215,7 +214,8 @@ public class ReturnWSService {
 
 								ScoreEvaluation scoreEvaluation = new ScoreEvaluation(qtiResultSet.getScore(), qtiResultSet.getIsPassed(), qtiResultSet.getFullyAssessed(),
 										qtiResultSet.getAssessmentID());
-								am.syncAndsaveScoreEvaluation(courseNode, assessedIdentity, assessedIdentity, scoreEvaluation, false, userCourseEnvironment, cpm);
+								am.saveScoreEvaluation(courseNode, null, assessedIdentity, scoreEvaluation, userCourseEnvironment, false);
+
 							}
 						} else {
 							if (log.isDebug()) {
diff --git a/src/main/java/org/olat/admin/landingpages/ui/LandingPagesAdminController.java b/src/main/java/org/olat/admin/landingpages/ui/LandingPagesAdminController.java
index 12d19100fc3d6e775d9380b28315c3d88ba76731..2d3c16c7826a8de3c8a3d452e76b3cbc8e29671c 100644
--- a/src/main/java/org/olat/admin/landingpages/ui/LandingPagesAdminController.java
+++ b/src/main/java/org/olat/admin/landingpages/ui/LandingPagesAdminController.java
@@ -53,7 +53,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
 import org.olat.core.gui.components.velocity.VelocityContainer;
@@ -139,12 +138,12 @@ public class LandingPagesAdminController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(RCols.landingPage.i18nKey(), RCols.landingPage.ordinal()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(RCols.landingPageChooser.i18nKey(), RCols.landingPageChooser.ordinal()));
 		
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("up", -1, "up",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("up", -1, "up",
 				new StaticFlexiCellRenderer("", "up", "o_icon o_icon-lg o_icon_move_up",translate("up"))));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("down", -1, "down",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("down", -1, "down",
 				new StaticFlexiCellRenderer("", "down", "o_icon o_icon-lg o_icon_move_down", translate("down"))));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("add", translate("add"), "add"));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", translate("delete"), "delete"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("add", translate("add"), "add"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete"));
 
 		//pack the rules
 		Rules rules = lpModule.getRules();
diff --git a/src/main/java/org/olat/admin/site/ui/SitesConfigurationController.java b/src/main/java/org/olat/admin/site/ui/SitesConfigurationController.java
index 757d9244041515f5694928f01e9b877d8817e800..4674ca9959f5e3cff8200be166120935a3730006 100644
--- a/src/main/java/org/olat/admin/site/ui/SitesConfigurationController.java
+++ b/src/main/java/org/olat/admin/site/ui/SitesConfigurationController.java
@@ -41,7 +41,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.navigation.SiteAlternativeControllerCreator;
@@ -136,9 +135,9 @@ public class SitesConfigurationController extends FormBasicController {
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(SiteCols.altController.i18nKey(), SiteCols.altController.ordinal()));
 		}
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, SiteCols.defaultOrder.i18nKey(), SiteCols.defaultOrder.ordinal(), false, null));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("up", SiteCols.up.ordinal(), "up",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("up", SiteCols.up.ordinal(), "up",
 				new StaticFlexiCellRenderer("", "up", "o_icon o_icon-lg o_icon_move_up", translate("up"))));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("down", SiteCols.down.ordinal(), "down",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("down", SiteCols.down.ordinal(), "down",
 				new StaticFlexiCellRenderer("", "down", "o_icon o_icon-lg o_icon_move_down", translate("down"))));
 
 		model = new SiteDefModel(columnsModel);
diff --git a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
index 0af9923e07732f5fd9e460e28f544500f479015c..69ca37a8ab984a500a6b56c3bda4fac8d07dc5eb 100644
--- a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
+++ b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
@@ -44,7 +44,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFle
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -213,7 +212,7 @@ public class UserSearchFlexiController extends FlexiAutoCompleterController {
 					tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(), colPos++));
 				}
 			}
-			tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translate("select"), "select"));
+			tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select"));
 			
 			Translator myTrans = userManager.getPropertyHandlerTranslator(getTranslator());
 			userTableModel = new UserSearchFlexiTableModel(Collections.<Identity>emptyList(), resultingPropertyHandlers, isAdministrativeUser, getLocale(), tableColumnModel);
diff --git a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java
index 4cf7cea7cc09baa2f57d1bb691fb05e86180d8a9..55b19a06a64f2fe1852caa104259387832ebabf4 100644
--- a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java
+++ b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java
@@ -108,8 +108,8 @@ import org.olat.core.util.resource.OresHelper;
 import org.olat.course.assessment.AssessmentMode.Status;
 import org.olat.course.assessment.AssessmentModeNotificationEvent;
 import org.olat.course.assessment.model.TransientAssessmentMode;
-import org.olat.course.assessment.ui.AssessmentModeGuardController;
-import org.olat.course.assessment.ui.ChooseAssessmentModeEvent;
+import org.olat.course.assessment.ui.mode.AssessmentModeGuardController;
+import org.olat.course.assessment.ui.mode.ChooseAssessmentModeEvent;
 import org.olat.gui.control.UserToolsMenuController;
 import org.olat.home.HomeSite;
 import org.olat.login.AfterLoginInterceptionController;
diff --git a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
index e4f0bb7550b6386cf65e8bffe83d2f4420660007..b94733d852e7a9d885475effc04d4d3c2fee4c1b 100644
--- a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
+++ b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
@@ -131,6 +131,7 @@
 		<class>org.olat.ims.qti.statistics.model.QTIStatisticResult</class>
 		<class>org.olat.ims.qti.statistics.model.QTIStatisticResultSet</class>
 		<class>org.olat.ims.qti21.model.jpa.UserTestSessionImpl</class>
+		<class>org.olat.modules.assessment.model.AssessmentEntryImpl</class>
 		<class>org.olat.modules.qpool.model.PoolImpl</class>
 		<class>org.olat.modules.qpool.model.PoolToItem</class>
 		<class>org.olat.modules.qpool.model.PoolItemShortView</class>
diff --git a/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml b/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml
index 84b11a62c11011109b3b87847edada3d520b7d7f..4db7eeb0244441f092fdb7fd39d31a350c6f0460 100644
--- a/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml
+++ b/src/main/java/org/olat/core/commons/services/notifications/_spring/notificationsContext.xml
@@ -7,7 +7,6 @@
 
 	<!-- List of notifications handlers -->
 	<bean id="org.olat.modules.fo.ForumNotificationsHandler" class="org.olat.modules.fo.ForumNotificationsHandler" />
-	<bean id="org.olat.course.assessment.AssessmentNotificationsHandler" class="org.olat.course.assessment.AssessmentNotificationsHandler" />
 	<bean id="org.olat.core.commons.modules.bc.FolderNotificationsHandler" class="org.olat.core.commons.modules.bc.notifications.FolderNotificationsHandler" />
 	<bean id="org.olat.modules.dialog.FileUploadNotificationHandler" class="org.olat.modules.dialog.FileUploadNotificationHandler" />
 	<bean id="org.olat.course.nodes.ta.DropboxFileUploadNotificationHandler" class="org.olat.course.nodes.ta.DropboxFileUploadNotificationHandler" />
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiColumnModel.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiColumnModel.java
deleted file mode 100644
index 3516227520efeeb1e11fec8d4b1946c7c8eefb1c..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiColumnModel.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.gui.components.form.flexible.impl.elements.table;
-
-/**
- * 
- * Initial date: 15.02.2013<br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- *
- */
-public abstract class AbstractFlexiColumnModel implements FlexiColumnModel {
-
-	private int alignment;
-	private String headerKey;
-	private String headerLabel;
-	private String columnKey;
-	private boolean sortable;
-	private boolean exportable = true;
-	private String sortedKey;
-	private int columnIndex;
-	private FlexiCellRenderer cellRenderer;
-
-	public AbstractFlexiColumnModel(String headerKey, int columnIndex, int alignment, FlexiCellRenderer cellRenderer) {
-		this(headerKey, columnIndex, alignment, false, null, cellRenderer);
-	}
-	
-	public AbstractFlexiColumnModel(String headerKey, int columnIndex, int alignment,
-			boolean sortable, String sortedKey, FlexiCellRenderer cellRenderer) {
-		this.headerKey = headerKey;
-		this.columnIndex = columnIndex;
-		this.columnKey = headerKey.replace(".", "").toLowerCase();
-		this.sortable = sortable;
-		this.sortedKey = sortedKey;
-		this.alignment = alignment;
-		this.cellRenderer = cellRenderer;
-	}
-	
-	@Override
-	public String getAction() {
-		return null;
-	}
-
-	public String getHeaderKey() {
-		return headerKey;
-	}
-	
-	@Override
-	public String getHeaderLabel() {
-		return headerLabel;
-	}
-	
-	public void setHeaderLabel(String headerLabel) {
-		this.headerLabel = headerLabel;
-	}
-
-	@Override
-	public String getColumnKey() {
-		return columnKey;
-	}
-
-	@Override
-	public int getColumnIndex() {
-		return columnIndex;
-	}
-
-	@Override
-	public boolean isSortable() {
-		return sortable;
-	}
-
-	@Override
-	public void setSortable(boolean sortable) {
-		this.sortable = sortable;
-	}
-
-	@Override
-	public boolean isExportable() {
-		return exportable;
-	}
-
-	@Override
-	public void setExportable(boolean exportable) {
-		this.exportable = exportable;
-	}
-
-	@Override
-	public boolean isDefaultVisible() {
-		return true;
-	}
-
-	@Override
-	public String getSortKey() {
-		return sortedKey;
-	}
-
-	@Override
-	public void setSortKey(String sortedKey) {
-		this.sortedKey = sortedKey;
-	}
-
-	public int getAlignment() {
-		return alignment;
-	}
-
-	public void setAlignment(int alignment) {
-		this.alignment = alignment;
-	}
-
-	public void setCellRenderer(FlexiCellRenderer cellRenderer) {
-		this.cellRenderer = cellRenderer;
-	}
-
-	public FlexiCellRenderer getCellRenderer() {
-		return cellRenderer;
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java
index ead0aa3f6862bcca2f4c26f531ffc3d94e8b97e3..4c1369fb0fbdeec4bbe3c8a909f24e1a62103ad4 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java
@@ -43,31 +43,99 @@ public class DefaultFlexiColumnModel implements FlexiColumnModel {
 	private String sortedKey;
 
 	private boolean defaultVisible;
+	private boolean alwaysVisible;
 	private int alignment;
+	
+	private final String action;
+	
 	private FlexiCellRenderer cellRenderer;
+	
+	public DefaultFlexiColumnModel(FlexiColumnDef def) {
+		this(def.i18nHeaderKey(), def.ordinal(), false, null);
+	}
+	
+	public DefaultFlexiColumnModel(FlexiColumnDef def, String action) {
+		this(true, false, def.i18nHeaderKey(), def.ordinal(), action, false, null, FlexiColumnModel.ALIGNMENT_LEFT, 
+				new StaticFlexiCellRenderer(action, new TextFlexiCellRenderer()));
+	}
 
+	/**
+	 * 
+	 * @param headerKey
+	 * @param columnIndex
+	 */
 	public DefaultFlexiColumnModel(String headerKey, int columnIndex) {
 		this(headerKey, columnIndex, false, null);
 	}
 	
+	/**
+	 * Always visible
+	 * @param headerKey
+	 * @param label
+	 * @param action
+	 */
+	public DefaultFlexiColumnModel(String headerKey, String label, String action) {
+		this(true, true, headerKey, -1, action, false, null, FlexiColumnModel.ALIGNMENT_LEFT, new StaticFlexiCellRenderer(label, action));
+	}
+	
 	public DefaultFlexiColumnModel(String headerKey, int columnIndex, boolean sortable, String sortKey) {
-		this(true, headerKey, columnIndex, sortable, sortKey, FlexiColumnModel.ALIGNMENT_LEFT,  new TextFlexiCellRenderer());
+		this(true, false, headerKey, columnIndex, null, sortable, sortKey, FlexiColumnModel.ALIGNMENT_LEFT, new TextFlexiCellRenderer());
+	}
+	
+	public DefaultFlexiColumnModel(FlexiColumnDef def, FlexiCellRenderer renderer) {
+		this(true, false, def.i18nHeaderKey(), def.ordinal(), null, false, null, FlexiColumnModel.ALIGNMENT_LEFT, renderer);
 	}
 	
 	public DefaultFlexiColumnModel(String headerKey, int columnIndex, FlexiCellRenderer renderer) {
-		this(true, headerKey, columnIndex, false, null, FlexiColumnModel.ALIGNMENT_LEFT, renderer);
+		this(true, false, headerKey, columnIndex, null, false, null, FlexiColumnModel.ALIGNMENT_LEFT, renderer);
+	}
+	
+	/**
+	 * Always visible
+	 * @param headerKey
+	 * @param columnIndex
+	 * @param action
+	 * @param renderer
+	 */
+	public DefaultFlexiColumnModel(String headerKey, int columnIndex, String action, FlexiCellRenderer renderer) {
+		this(true, true, headerKey, columnIndex, action, false, null, FlexiColumnModel.ALIGNMENT_LEFT, renderer);
 	}
 	
 	public DefaultFlexiColumnModel(String headerKey, int columnIndex, boolean sortable, String sortKey, FlexiCellRenderer renderer) {
-		this(true, headerKey, columnIndex, sortable, sortKey, FlexiColumnModel.ALIGNMENT_LEFT, renderer);
+		this(true, false, headerKey, columnIndex, null, sortable, sortKey, FlexiColumnModel.ALIGNMENT_LEFT, renderer);
 	}
 	
 	public DefaultFlexiColumnModel(boolean defVisible, String headerKey, int columnIndex, boolean sortable, String sortKey) {
-		this(defVisible, headerKey, columnIndex, sortable, sortKey, FlexiColumnModel.ALIGNMENT_LEFT,  new TextFlexiCellRenderer());
+		this(defVisible, false, headerKey, columnIndex, null, sortable, sortKey, FlexiColumnModel.ALIGNMENT_LEFT,
+				new TextFlexiCellRenderer());
+	}
+	
+	public DefaultFlexiColumnModel(boolean defVisible, String headerKey, int columnIndex, String action, boolean sortable, String sortKey) {
+		this(defVisible, false, headerKey, columnIndex, action, sortable, sortKey, FlexiColumnModel.ALIGNMENT_LEFT,
+				new StaticFlexiCellRenderer(action, new TextFlexiCellRenderer()));
+	}
+	
+	/**
+	 * Always visible
+	 * @param headerKey
+	 * @param columnIndex
+	 * @param action
+	 * @param sortable
+	 * @param sortedKey
+	 * @param renderer
+	 */
+	public DefaultFlexiColumnModel(String headerKey, int columnIndex, String action, boolean sortable, String sortedKey, FlexiCellRenderer renderer) {
+		this(true, true, headerKey, columnIndex, action, sortable, sortedKey, FlexiColumnModel.ALIGNMENT_LEFT, renderer);
 	}
 	
 	public DefaultFlexiColumnModel(boolean defVisible, String headerKey, int columnIndex, boolean sortable, String sortKey, int alignment, FlexiCellRenderer cellRenderer) {
+		this(defVisible, false, headerKey, columnIndex, null, sortable, sortKey, alignment, cellRenderer);
+	}
+	
+	public DefaultFlexiColumnModel(boolean defVisible, boolean alwaysVisible, String headerKey, int columnIndex, String action,
+			boolean sortable, String sortKey, int alignment, FlexiCellRenderer cellRenderer) {
 		this.defaultVisible = defVisible;
+		this.alwaysVisible = alwaysVisible;
 		this.sortable = sortable;
 		this.sortedKey = sortKey;
 		this.headerKey = headerKey;
@@ -75,16 +143,17 @@ public class DefaultFlexiColumnModel implements FlexiColumnModel {
 		this.columnKey = headerKey.replace(".", "").toLowerCase();
 		this.alignment = alignment;
 		this.cellRenderer = cellRenderer;
+		this.action = action;
 	}
 
 	@Override
 	public boolean isAlwaysVisible() {
-		return false;
+		return alwaysVisible;
 	}
 
 	@Override
 	public String getAction() {
-		return null;
+		return action;
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiColumnDef.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiColumnDef.java
new file mode 100644
index 0000000000000000000000000000000000000000..6aa159b81dc56353ec15856bdaeee8c4b6b40e77
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiColumnDef.java
@@ -0,0 +1,34 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.gui.components.form.flexible.impl.elements.table;
+
+/**
+ * 
+ * Initial date: 22.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface FlexiColumnDef {
+	
+	public int ordinal();
+	
+	public String i18nHeaderKey();
+
+}
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiSortableColumnDef.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiSortableColumnDef.java
new file mode 100644
index 0000000000000000000000000000000000000000..41220754517fe8f34d5d6b4358d276bca3295f1e
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiSortableColumnDef.java
@@ -0,0 +1,34 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.gui.components.form.flexible.impl.elements.table;
+
+/**
+ * 
+ * Initial date: 22.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface FlexiSortableColumnDef extends FlexiColumnDef {
+	
+	public boolean sortable();
+	
+	public String sortKey();
+
+}
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiColumnModel.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiColumnModel.java
deleted file mode 100644
index d6a6b9e863c3c2afb5ded834e6d89a7be8937060..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/StaticFlexiColumnModel.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.gui.components.form.flexible.impl.elements.table;
-
-/**
- * 
- * Initial date: 15.02.2013<br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- *
- */
-public class StaticFlexiColumnModel extends AbstractFlexiColumnModel {
-
-	private final String action;
-	
-	/**
-	 * Used the standard renderer
-	 * @param headerKey
-	 * @param label
-	 * @param action
-	 */
-	public StaticFlexiColumnModel(String headerKey, String label, String action) {
-		super(headerKey, -1, FlexiColumnModel.ALIGNMENT_LEFT, new StaticFlexiCellRenderer(label, action));
-		this.action = action;
-	}
-	
-	/**
-	 * Use a custom renderer
-	 * @param headerKey
-	 * @param columnIndex
-	 * @param action
-	 * @param renderer
-	 */
-	public StaticFlexiColumnModel(String headerKey, int columnIndex, String action, FlexiCellRenderer renderer) {
-		super(headerKey, columnIndex, FlexiColumnModel.ALIGNMENT_LEFT, renderer);
-		this.action = action;
-	}
-	
-	public StaticFlexiColumnModel(String headerKey, int columnIndex, String action, boolean sortable, String sortedKey, FlexiCellRenderer renderer) {
-		super(headerKey, columnIndex, FlexiColumnModel.ALIGNMENT_LEFT, sortable, sortedKey, renderer);
-		this.action = action;
-	}
-
-	@Override
-	public boolean isAlwaysVisible() {
-		return true;
-	}
-
-	@Override
-	public String getAction() {
-		return action;
-	}
-}
diff --git a/src/main/java/org/olat/course/assessment/AssessmentHelper.java b/src/main/java/org/olat/course/assessment/AssessmentHelper.java
index 14aff5c5d15cb0016c88b6284a1810eaf7d5da3e..e2de2a74b674386194a128589bc00191cf322b95 100644
--- a/src/main/java/org/olat/course/assessment/AssessmentHelper.java
+++ b/src/main/java/org/olat/course/assessment/AssessmentHelper.java
@@ -25,6 +25,7 @@
 
 package org.olat.course.assessment;
 
+import java.math.BigDecimal;
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
 import java.text.ParseException;
@@ -243,12 +244,18 @@ public class AssessmentHelper {
 
 		return nodes;
 	}
+	
+	public static String getRoundedScore(BigDecimal score) {
+		if (score == null) return null;
+		
+		Float fscore = score.floatValue();
+		return getRoundedScore(fscore); 
+	}
 
 	/**
 	 * @param score The score to be rounded
 	 * @return The rounded score for GUI presentation
 	 */
-	//fxdiff VCRP-4: assessment overview with max score
 	public static String getRoundedScore(Float score) {
 		if (score == null) return null;
 
@@ -256,7 +263,6 @@ public class AssessmentHelper {
 		synchronized(scoreFormat) {
 			return scoreFormat.format(score);
 		}
-		//return Formatter.roundToString(score.floatValue(), 3);
 	}
 	
 	public static Float getRoundedScore(String score) {
diff --git a/src/main/java/org/olat/course/assessment/AssessmentMainController.java b/src/main/java/org/olat/course/assessment/AssessmentMainController.java
index 374806d854636a23277678fea8f50960df3e6fef..d702acd669bf446df9a096bf7c34fa0b2ed12ee1 100644
--- a/src/main/java/org/olat/course/assessment/AssessmentMainController.java
+++ b/src/main/java/org/olat/course/assessment/AssessmentMainController.java
@@ -96,6 +96,7 @@ import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.NodeTableDataModel.Cols;
 import org.olat.course.assessment.bulk.BulkAssessmentOverviewController;
+import org.olat.course.assessment.manager.AssessmentNotificationsHandler;
 import org.olat.course.assessment.manager.UserCourseInformationsManager;
 import org.olat.course.certificate.CertificateEvent;
 import org.olat.course.certificate.CertificateLight;
@@ -234,6 +235,8 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 	private BusinessGroupService businessGroupService;
 	@Autowired
 	private CertificatesManager certificatesManager;
+	@Autowired
+	private AssessmentNotificationsHandler assessmentNotificationsHandler;
 	
 	/**
 	 * Constructor for the assessment tool controller. 
@@ -284,10 +287,11 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 			
 		if (hasAssessableNodes) {
 			index.contextPut("hasAssessableNodes", new Boolean(hasAssessableNodes));
-			
-			// --- assessment notification subscription ---
-			csc = AssessmentUIFactory.createContextualSubscriptionController(ureq, wControl, course);
-			if (csc != null) {
+
+			SubscriptionContext subsContext = assessmentNotificationsHandler.getAssessmentSubscriptionContext(ureq.getIdentity(), course);
+			if (subsContext != null) {
+				PublisherData pData = assessmentNotificationsHandler.getAssessmentPublisherData(course, wControl.getBusinessControl().getAsString());
+				csc = new ContextualSubscriptionController(ureq, wControl, subsContext, pData);
 				listenTo(csc); // cleanup on dispose
 				index.put("assessmentSubscription", csc.getInitialComponent());
 			}
diff --git a/src/main/java/org/olat/course/assessment/AssessmentManager.java b/src/main/java/org/olat/course/assessment/AssessmentManager.java
index 313408bfb3a89afb737fa09548f920f366f0c904..3a01ddc8098c2c4e14b4c41227d7b46cdb47035e 100644
--- a/src/main/java/org/olat/course/assessment/AssessmentManager.java
+++ b/src/main/java/org/olat/course/assessment/AssessmentManager.java
@@ -34,6 +34,7 @@ import org.olat.core.util.event.GenericEventListener;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.modules.assessment.AssessmentEntry;
 
 /**
  * Description:<BR>
@@ -52,6 +53,7 @@ import org.olat.course.run.userview.UserCourseEnvironment;
 public interface AssessmentManager {
 
 	// Names used to save user data in the properties table
+	/*
 	public static final String SCORE = "SCORE";
 	public static final String PASSED = "PASSED";
 	public static final String ATTEMPTS = "ATTEMPTS";
@@ -60,6 +62,7 @@ public interface AssessmentManager {
 	public static final String ASSESSMENT_ID = "ASSESSMENT_ID";
 
 	public final static String FULLY_ASSESSED = "FULLY_ASSESSED";
+	*/
 	
 	/**
 	 * Load all persisted assessment data into a local cache if such a cache is available
@@ -208,4 +211,5 @@ public interface AssessmentManager {
 	 */
 	public Boolean getNodeFullyAssessed(CourseNode courseNode, Identity identity);
 
+	public List<AssessmentEntry> getAssessmentData(CourseNode courseNode);
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/assessment/AssessmentToolManager.java b/src/main/java/org/olat/course/assessment/AssessmentToolManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..4408a90122b81b98c65092312ffb52a0f4cb80e1
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/AssessmentToolManager.java
@@ -0,0 +1,39 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment;
+
+import java.util.List;
+
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.model.SearchAssessedIdentityParams;
+
+/**
+ * The manager taylored for the assessment tool.
+ * 
+ * 
+ * Initial date: 22.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface AssessmentToolManager {
+	
+	public List<Identity> getAssessedIdentityWithCertificates(SearchAssessedIdentityParams params);
+
+}
diff --git a/src/main/java/org/olat/course/assessment/AssessmentUIFactory.java b/src/main/java/org/olat/course/assessment/AssessmentUIFactory.java
deleted file mode 100644
index 42f0be22fd3d145cd776cb36309fb5dd065c9b83..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/course/assessment/AssessmentUIFactory.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <p>
-* Licensed under the Apache License, Version 2.0 (the "License"); <br>
-* you may not use this file except in compliance with the License.<br>
-* You may obtain a copy of the License at
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <p>
-* Unless required by applicable law or agreed to in writing,<br>
-* software distributed under the License is distributed on an "AS IS" BASIS, <br>
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
-* See the License for the specific language governing permissions and <br>
-* limitations under the License.
-* <p>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.
-*/
-package org.olat.course.assessment;
-
-import org.olat.core.commons.services.notifications.PublisherData;
-import org.olat.core.commons.services.notifications.SubscriptionContext;
-import org.olat.core.commons.services.notifications.ui.ContextualSubscriptionController;
-import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.control.WindowControl;
-import org.olat.course.ICourse;
-
-/**
- * Description:<br>
- * TODO: patrickb Class Description for AssessmentUIFactory
- * 
- * <P>
- * Initial Date:  29.06.2010 <br>
- * @author patrickb
- */
-public class AssessmentUIFactory {
-	
-	/**
-	 * 
-	 * @param ureq
-	 * @param wControl
-	 * @param course
-	 * @return null if no contextualSubscriptionController is available
-	 */
-	public static Controller createContextualSubscriptionController(UserRequest ureq, WindowControl wControl, ICourse course){
-		AssessmentNotificationsHandler anh = AssessmentNotificationsHandler.getInstance();
-		SubscriptionContext subsContext = anh.getAssessmentSubscriptionContext(ureq.getIdentity(), course);
-		if (subsContext != null) {
-			PublisherData pData = anh.getAssessmentPublisherData(course, wControl.getBusinessControl().getAsString());
-			return new ContextualSubscriptionController(ureq, wControl, subsContext, pData);
-		}
-		return null;
-	}
-}
diff --git a/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java b/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java
index eaf931ac397090878857a08e476d38faacd64edc..14be0f81eea0b479bf65238b284e1ac5b8decbf0 100644
--- a/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java
+++ b/src/main/java/org/olat/course/assessment/EfficiencyStatementManager.java
@@ -128,7 +128,7 @@ public class EfficiencyStatementManager extends BasicManager implements UserData
 	 * Called in AssessmentManager in a <code>doInSync</code> block, toghether with the saveScore.
 	 * @param userCourseEnv
 	 */
-	protected void updateUserEfficiencyStatement(UserCourseEnvironment userCourseEnv) {
+	public void updateUserEfficiencyStatement(UserCourseEnvironment userCourseEnv) {
 		Long courseResId = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); 
 		OLATResourceable courseOres = OresHelper.createOLATResourceableInstance(CourseModule.class, courseResId);
 		RepositoryEntry re = repositoryManager.lookupRepositoryEntry(courseOres, false);
diff --git a/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml b/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml
index c94ace250abcf9cc98301d5234e7a931c3485a4c..3d1a18c13dd43a9134b2a9dcd1778e99a5505188 100644
--- a/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml
+++ b/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml
@@ -31,13 +31,13 @@
 		<property name="order" value="8206" />
 		<property name="actionController">	
 			<bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype">
-				<property name="className" value="org.olat.course.assessment.ui.AssessmentModeAdminController"/>
+				<property name="className" value="org.olat.course.assessment.ui.mode.AssessmentModeAdminController"/>
 			</bean>
 		</property>
 		<property name="navigationKey" value="certificates" />
 		<property name="i18nActionKey" value="admin.menu.title"/>
 		<property name="i18nDescriptionKey" value="admin.menu.title.alt"/>
-		<property name="translationPackage" value="org.olat.course.assessment.ui"/>
+		<property name="translationPackage" value="org.olat.course.assessment.ui.mode"/>
 		<property name="parentTreeNodeIdentifier" value="modulesParent" /> 
 		<property name="extensionPoints">
 			<list>	
diff --git a/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentOverviewController.java b/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentOverviewController.java
index d158e3c2d3e9583c218b6868dbfafd67f3fe8716..041ac112fd651a5eedc277acf24b9e3f94f131cd 100644
--- a/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentOverviewController.java
+++ b/src/main/java/org/olat/course/assessment/bulk/BulkAssessmentOverviewController.java
@@ -42,7 +42,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
@@ -118,11 +117,11 @@ public class BulkAssessmentOverviewController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.numOfAssessedUsers", Cols.numOfAssessedUsers.ordinal()));
 		
 		FlexiCellRenderer renderer = new StaticFlexiCellRenderer("select-owner", new TextFlexiCellRenderer());
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.owner", Cols.owner.ordinal(), "select-owner", renderer));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.owner", Cols.owner.ordinal(), "select-owner", renderer));
 		
 		
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("edit", translate("edit"), "edit"));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", translate("delete"), "delete"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate("edit"), "edit"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete"));
 		
 		taskModel = new TaskDataModel(Collections.<TaskData>emptyList(), columnsModel);
 		taskListEl = uifactory.addTableElement(getWindowControl(), "taskList", taskModel, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/course/assessment/bulk/SelectCourseNodeStepForm.java b/src/main/java/org/olat/course/assessment/bulk/SelectCourseNodeStepForm.java
index 04c8d88683dfc5d58f5fd127ef8683c6934889a3..55b69fbdd7516e1e4e29e0daef685168126c0023 100644
--- a/src/main/java/org/olat/course/assessment/bulk/SelectCourseNodeStepForm.java
+++ b/src/main/java/org/olat/course/assessment/bulk/SelectCourseNodeStepForm.java
@@ -36,7 +36,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.table.DefaultTableDataModel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
@@ -80,7 +79,7 @@ public class SelectCourseNodeStepForm extends StepFormBasicController {
 		FlexiTableColumnModel tableColumnModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, "table.header.node",
 				Cols.node.ordinal(), false, null, FlexiColumnModel.ALIGNMENT_LEFT, new CourseNodeRenderer()));
-		tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.action.select",
+		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.action.select",
 				Cols.assessable.ordinal(), "select",
 				new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("table.action.select"), "select"), null)));
 		tableModel.setTableColumnModel(tableColumnModel);
diff --git a/src/main/java/org/olat/course/assessment/AssessmentNotificationsHandler.java b/src/main/java/org/olat/course/assessment/manager/AssessmentNotificationsHandler.java
similarity index 77%
rename from src/main/java/org/olat/course/assessment/AssessmentNotificationsHandler.java
rename to src/main/java/org/olat/course/assessment/manager/AssessmentNotificationsHandler.java
index 6c4d7355c9e700eeba36aa9e9922a7320826f705..ead32f35b68ad0448e011bb666e3a91e8a41a7fc 100644
--- a/src/main/java/org/olat/course/assessment/AssessmentNotificationsHandler.java
+++ b/src/main/java/org/olat/course/assessment/manager/AssessmentNotificationsHandler.java
@@ -23,20 +23,19 @@
 * under the Apache 2.0 license as the original file.
 */
 
-package org.olat.course.assessment;
+package org.olat.course.assessment.manager;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Date;
-import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
+import java.util.Set;
 
-import org.olat.basesecurity.BaseSecurityManager;
+import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.GroupRoles;
-import org.olat.core.CoreSpringFactory;
-import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.commons.services.notifications.NotificationHelper;
 import org.olat.core.commons.services.notifications.NotificationsHandler;
 import org.olat.core.commons.services.notifications.NotificationsManager;
@@ -60,6 +59,7 @@ import org.olat.course.CourseFactory;
 import org.olat.course.CourseModule;
 import org.olat.course.ICourse;
 import org.olat.course.Structure;
+import org.olat.course.assessment.AssessmentHelper;
 import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.groupsandrights.CourseRights;
 import org.olat.course.nodes.AssessableCourseNode;
@@ -67,13 +67,14 @@ import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.CourseNodeFactory;
 import org.olat.course.nodes.STCourseNode;
 import org.olat.course.nodes.ScormCourseNode;
-import org.olat.course.properties.CoursePropertyManager;
-import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupService;
+import org.olat.modules.assessment.AssessmentEntry;
+import org.olat.modules.assessment.manager.AssessmentEntryDAO;
 import org.olat.modules.scorm.assessment.ScormAssessmentManager;
-import org.olat.properties.Property;
 import org.olat.repository.RepositoryManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
 
 /**
  * Description:<br>
@@ -84,26 +85,23 @@ import org.olat.repository.RepositoryManager;
  * 
  * @author Roberto Bagnoli
  */
+@Service
 public class AssessmentNotificationsHandler implements NotificationsHandler {
 	private static final OLog log = Tracing.createLoggerFor(AssessmentNotificationsHandler.class);
 	
 	private static final String CSS_CLASS_USER_ICON = "o_icon_user";
-	private static AssessmentNotificationsHandler INSTANCE;
-	private Map<Long,SubscriptionContext> subsContexts = new HashMap<Long,SubscriptionContext>();
 
-	/**
-	 * Don't use this! Always use the getInstance() method. This is only used once by Spring!
-	 */
-	public AssessmentNotificationsHandler() {
-		INSTANCE = this;
-	}
+	@Autowired
+	private BaseSecurity securityManager;
+	@Autowired
+	private RepositoryManager repositoryManager;
+	@Autowired
+	private NotificationsManager notificationsManager;
+	@Autowired
+	private BusinessGroupService businessGroupService;
+	@Autowired
+	private AssessmentEntryDAO courseNodeAssessmentDao;
 
-	/**
-	 * @return the singleton instance
-	 */
-	public static AssessmentNotificationsHandler getInstance() {
-		return INSTANCE;
-	}
 
 	/**
 	 * Returns the <code>SubscriptionContext</code> to use for assessment
@@ -122,27 +120,18 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 	 *         identity associated to the request is not allowed to be notified
 	 * @see #canSubscribeForAssessmentNotification(Identity, ICourse)
 	 */
-	protected SubscriptionContext getAssessmentSubscriptionContext(Identity ident, ICourse course) {
+	public SubscriptionContext getAssessmentSubscriptionContext(Identity ident, ICourse course) {
 		SubscriptionContext sctx = null;
-
 		if (ident == null || canSubscribeForAssessmentNotification(ident, course)) {
 			// Creates a new SubscriptionContext only if not found into cache
-			Long courseId = course.getResourceableId();
-			synchronized (subsContexts) { //o_clusterOK by:ld - no problem to have independent subsContexts caches for each cluster node
-				sctx = subsContexts.get(courseId);
-				if (sctx == null) {
-					// a subscription context showing to the root node (the course's root
-					// node is started when clicking such a notification)
-					CourseNode cn = course.getRunStructure().getRootNode();
-					CourseEnvironment ce = course.getCourseEnvironment();
-					//FIXME:fg:b little problem is that the assessment tool and the course are not "the same" anymore, that is you can open the same course twice in the
-					// dynamic tabs by a) klicking e.g. via repo, and b via notifications link to the assementtool
-					sctx = new SubscriptionContext(CourseModule.ORES_COURSE_ASSESSMENT, ce.getCourseResourceableId(), cn.getIdent());
-					subsContexts.put(courseId, sctx);
-				}
+			if (sctx == null) {
+				// a subscription context showing to the root node (the course's root
+				// node is started when clicking such a notification)
+				CourseNode cn = course.getRunStructure().getRootNode();
+				Long resourceableId = course.getResourceableId();
+				sctx = new SubscriptionContext(CourseModule.ORES_COURSE_ASSESSMENT, resourceableId, cn.getIdent());
 			}
 		}
-
 		return sctx;
 	}
 
@@ -208,7 +197,7 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 	private void markPublisherNews(Identity ident, ICourse course) {
 		SubscriptionContext subsContext = getAssessmentSubscriptionContext(course);
 		if (subsContext != null) {
-			NotificationsManager.getInstance().markPublisherNews(subsContext, ident, true);
+			notificationsManager.markPublisherNews(subsContext, ident, true);
 		}
 	}
 
@@ -233,7 +222,7 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 
 		CourseGroupManager grpMan = course.getCourseEnvironment().getCourseGroupManager();
 		
-		boolean isInstitutionalResourceManager = BaseSecurityManager.getInstance().isIdentityInSecurityGroup(ident, BaseSecurityManager.getInstance().findSecurityGroupByName(Constants.GROUP_INST_ORES_MANAGER));
+		boolean isInstitutionalResourceManager = securityManager.isIdentityInSecurityGroup(ident, securityManager.findSecurityGroupByName(Constants.GROUP_INST_ORES_MANAGER));
 		return isInstitutionalResourceManager || grpMan.isIdentityCourseAdministrator(ident) || grpMan.isIdentityCourseCoach(ident) || grpMan.hasRight(ident, CourseRights.RIGHT_ASSESSMENT);
 	}
 
@@ -307,8 +296,8 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 		Publisher p = subscriber.getPublisher();
 		if(!NotificationsUpgradeHelper.checkCourse(p)) {
 			//course don't exist anymore
-			NotificationsManager.getInstance().deactivate(p);
-			return NotificationsManager.getInstance().getNoSubscriptionInfo();
+			notificationsManager.deactivate(p);
+			return notificationsManager.getNoSubscriptionInfo();
 		}
 		
 		try {
@@ -318,7 +307,7 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 			// do not try to create a subscription info if state is deleted - results in
 			// exceptions, course
 			// can't be loaded when already deleted
-			if (NotificationsManager.getInstance().isPublisherValid(p) && compareDate.before(latestNews)) {
+			if (notificationsManager.isPublisherValid(p) && compareDate.before(latestNews)) {
 				Long courseId = new Long(p.getData());
 				final ICourse course = loadCourseFromId(courseId);
 				if (course != null) {
@@ -327,37 +316,23 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 					CourseGroupManager cgm = course.getCourseEnvironment().getCourseGroupManager();
 					final boolean hasFullAccess = (cgm.isIdentityCourseAdministrator(identity) ? true : cgm.hasRight(identity,
 							CourseRights.RIGHT_ASSESSMENT));
-					final List<Identity> coachedUsers = new ArrayList<Identity>();
+					final Set<Identity> coachedUsers = new HashSet<Identity>();
 					if (!hasFullAccess) {
 						// initialize list of users, only when user has not full access
 						List<BusinessGroup> coachedGroups = cgm.getOwnedBusinessGroups(identity);
-						BusinessGroupService businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
 						List<Identity> coachedIdentites = businessGroupService.getMembers(coachedGroups, GroupRoles.participant.name());
 						coachedUsers.addAll(coachedIdentites);
 					}
 
 					List<AssessableCourseNode> testNodes = getCourseTestNodes(course);
 					Translator translator = Util.createPackageTranslator(AssessmentNotificationsHandler.class, locale);
-
-					
 					for (AssessableCourseNode test:testNodes) {
-						final CoursePropertyManager cpm = course.getCourseEnvironment().getCoursePropertyManager();
-						
-						List<Property> scoreProperties = cpm.listCourseNodeProperties(test, null, null, AssessmentManager.SCORE);
-						List<Property> attemptProperties = cpm.listCourseNodeProperties(test, null, null, AssessmentManager.ATTEMPTS);
-
-						for(Property attemptProperty:attemptProperties) {
-					  	Date modDate = attemptProperty.getLastModified();
-							Identity assessedIdentity = attemptProperty.getIdentity();
-					  	if (modDate.after(compareDate) && (hasFullAccess || PersistenceHelper.listContainsObjectByKey(coachedUsers, assessedIdentity))) {
-								String score = null;
-								for(Property scoreProperty:scoreProperties) {
-									if(scoreProperty.getIdentity().equalsByPersistableKey(assessedIdentity) ) {
-										score = scoreProperty.getFloatValue().toString();
-										break;
-									}
-								}
-								
+						List<AssessmentEntry> assessments = courseNodeAssessmentDao.loadAssessmentEntryBySubIdent(cgm.getCourseEntry(), test.getIdent());
+						for(AssessmentEntry assessment:assessments) {
+							Date modDate = assessment.getLastModified();
+							Identity assessedIdentity = assessment.getIdentity();
+							if (modDate.after(compareDate) && (hasFullAccess || coachedUsers.contains(assessedIdentity))) {
+								BigDecimal score = assessment.getScore();
 								if(test instanceof ScormCourseNode) {
 									ScormCourseNode scormTest = (ScormCourseNode)test;
 									//check if completed or passed
@@ -373,8 +348,9 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 									desc = translator.translate("notifications.entry.attempt", new String[] { test.getShortTitle(),
 											NotificationHelper.getFormatedName(assessedIdentity), type });
 								} else {
+									String scoreStr =AssessmentHelper.getRoundedScore(score);
 									desc = translator.translate("notifications.entry", new String[] { test.getShortTitle(),
-											NotificationHelper.getFormatedName(assessedIdentity), score, type });
+											NotificationHelper.getFormatedName(assessedIdentity), scoreStr, type });
 								}
 
 								String urlToSend = null;
@@ -397,13 +373,13 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 				}
 			} 
 			if(si == null) {
-				si = NotificationsManager.getInstance().getNoSubscriptionInfo();
+				si = notificationsManager.getNoSubscriptionInfo();
 			}
 			return si;
 		} catch (Exception e) {
 			log.error("Error while creating assessment notifications", e);
 			checkPublisher(p);
-			return NotificationsManager.getInstance().getNoSubscriptionInfo();
+			return notificationsManager.getNoSubscriptionInfo();
 		}
 	}
 	
@@ -411,7 +387,7 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 		try {
 			if(!NotificationsUpgradeHelper.checkCourse(p)) {
 				log.info("deactivating publisher with key; " + p.getKey(), null);
-				NotificationsManager.getInstance().deactivate(p);
+				notificationsManager.deactivate(p);
 			}
 		} catch (Exception e) {
 			log.error("", e);
@@ -422,10 +398,9 @@ public class AssessmentNotificationsHandler implements NotificationsHandler {
 	public String createTitleInfo(Subscriber subscriber, Locale locale) {
 		try {
 			Long resId = subscriber.getPublisher().getResId();
-			String displayName = RepositoryManager.getInstance().lookupDisplayNameByOLATResourceableId(resId);
+			String displayName = repositoryManager.lookupDisplayNameByOLATResourceableId(resId);
 			Translator trans = Util.createPackageTranslator(AssessmentNotificationsHandler.class, locale);
-			String title = trans.translate("notifications.title", new String[]{ displayName });
-			return title;
+			return trans.translate("notifications.title", new String[]{ displayName });
 		} catch (Exception e) {
 			log.error("Error while creating assessment notifications for subscriber: " + subscriber.getKey(), e);
 			checkPublisher(subscriber.getPublisher());
diff --git a/src/main/java/org/olat/course/assessment/manager/AssessmentToolManagerImpl.java b/src/main/java/org/olat/course/assessment/manager/AssessmentToolManagerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..a17ee2c257484454d31f8e520854b6eef62c330b
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/manager/AssessmentToolManagerImpl.java
@@ -0,0 +1,73 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.manager;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.olat.basesecurity.GroupRoles;
+import org.olat.basesecurity.IdentityImpl;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.AssessmentToolManager;
+import org.olat.course.assessment.model.AssessedIdentityWithCertificate;
+import org.olat.course.assessment.model.SearchAssessedIdentityParams;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * Work with the datas for the assessment tool
+ * 
+ * 
+ * Initial date: 21.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class AssessmentToolManagerImpl implements AssessmentToolManager{
+	
+	@Autowired
+	private DB dbInstance;
+	
+	@Override
+	public List<Identity> getAssessedIdentityWithCertificates(SearchAssessedIdentityParams params) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select ident")
+		  .append(" from ").append(IdentityImpl.class.getName()).append(" as ident ")
+		  .append(" where exists (")
+		  .append("  select infos from usercourseinfos infos where infos.identity=ident")
+		  .append("     and infos.resource.key=:resourceKey")
+		  .append(" ) or exists (select rel from repoentrytogroup as rel, bgroup as baseGroup, bgroupmember as membership")
+		  .append("    where rel.entry.key=:courseEntryKey and rel.group=baseGroup and membership.group=baseGroup and membership.identity=ident")
+		  .append("      and membership.role='").append(GroupRoles.participant.name()).append("'")
+		  .append(" )");
+		
+		List<Identity> list = dbInstance.getCurrentEntityManager()
+			.createQuery(sb.toString(), Identity.class)
+			.setParameter("courseEntryKey", params.getCourseEntry().getKey())
+			.setParameter("resourceKey", params.getCourseEntry().getOlatResource().getKey())
+			.getResultList();
+		return list;	
+	}
+	
+
+
+}
diff --git a/src/main/java/org/olat/course/assessment/manager/CourseAssessmentManagerImpl.java b/src/main/java/org/olat/course/assessment/manager/CourseAssessmentManagerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..2dc48da9ec9a12300b7b085bbf25e8f76ceb030f
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/manager/CourseAssessmentManagerImpl.java
@@ -0,0 +1,340 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.manager;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.id.Identity;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.logging.activity.StringResourceableType;
+import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.event.GenericEventListener;
+import org.olat.core.util.mail.MailerResult;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.assessment.AssessmentChangedEvent;
+import org.olat.course.assessment.AssessmentLoggingAction;
+import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.EfficiencyStatementManager;
+import org.olat.course.auditing.UserNodeAuditManager;
+import org.olat.course.certificate.CertificateTemplate;
+import org.olat.course.certificate.CertificatesManager;
+import org.olat.course.certificate.model.CertificateInfos;
+import org.olat.course.nodes.AssessableCourseNode;
+import org.olat.course.nodes.CourseNode;
+import org.olat.course.run.scoring.ScoreEvaluation;
+import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.modules.assessment.AssessmentEntry;
+import org.olat.modules.assessment.manager.AssessmentEntryDAO;
+import org.olat.repository.RepositoryEntry;
+import org.olat.util.logging.activity.LoggingResourceable;
+
+/**
+ * 
+ * Initial date: 20.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CourseAssessmentManagerImpl implements AssessmentManager {
+	
+	private static final Float FLOAT_ZERO = new Float(0);
+	private static final Integer INTEGER_ZERO = new Integer(0);
+	
+	private final RepositoryEntry courseEntry;
+	private final CertificatesManager certificatesManager;
+	private final AssessmentEntryDAO courseNodeAssessmentDao;
+	private final EfficiencyStatementManager efficiencyStatementManager;
+	
+	public CourseAssessmentManagerImpl(RepositoryEntry courseEntry) {
+		this.courseEntry = courseEntry;
+		certificatesManager = CoreSpringFactory.getImpl(CertificatesManager.class);
+		courseNodeAssessmentDao = CoreSpringFactory.getImpl(AssessmentEntryDAO.class);
+		efficiencyStatementManager = CoreSpringFactory.getImpl(EfficiencyStatementManager.class);
+	}
+	
+	private AssessmentEntry getOrCreate(Identity assessedIdentity, CourseNode courseNode) {
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.loadAssessmentEntry(assessedIdentity, courseEntry, courseNode.getIdent());
+		if(nodeAssessment == null) {
+			nodeAssessment = courseNodeAssessmentDao
+					.createCourseNodeAssessment(assessedIdentity, courseEntry,
+							courseNode.getIdent(), courseNode.getReferencedRepositoryEntry());
+		}
+		return nodeAssessment;
+	}
+
+	@Override
+	public List<AssessmentEntry> getAssessmentData(CourseNode courseNode) {
+		return courseNodeAssessmentDao.loadAssessmentEntryBySubIdent(courseEntry, courseNode.getIdent());
+	}
+
+	@Override
+	public void saveNodeAttempts(CourseNode courseNode, Identity identity, Identity assessedIdentity, Integer attempts) {
+		ICourse course = CourseFactory.loadCourse(courseEntry.getOlatResource());
+		
+		AssessmentEntry nodeAssessment = getOrCreate(assessedIdentity, courseNode);
+		nodeAssessment.setAttempts(attempts);
+		courseNodeAssessmentDao.updateCourseNodeAssessment(nodeAssessment);
+
+		//node log
+		UserNodeAuditManager am = course.getCourseEnvironment().getAuditManager();
+		am.appendToUserNodeLog(courseNode, identity, assessedIdentity, "ATTEMPTS set to: " + String.valueOf(attempts));
+
+		// notify about changes
+		AssessmentChangedEvent ace = new AssessmentChangedEvent(AssessmentChangedEvent.TYPE_ATTEMPTS_CHANGED, assessedIdentity);
+		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(ace, course);
+
+		// user activity logging
+		ThreadLocalUserActivityLogger.log(AssessmentLoggingAction.ASSESSMENT_ATTEMPTS_UPDATED, 
+				getClass(), 
+				LoggingResourceable.wrap(assessedIdentity), 
+				LoggingResourceable.wrapNonOlatResource(StringResourceableType.qtiAttempts, "", String.valueOf(attempts)));	
+	}
+
+	@Override
+	public void saveNodeComment(CourseNode courseNode, Identity identity, Identity assessedIdentity, String comment) {
+		ICourse course = CourseFactory.loadCourse(courseEntry.getOlatResource());
+		
+		AssessmentEntry nodeAssessment = getOrCreate(assessedIdentity, courseNode);
+		nodeAssessment.setComment(comment);
+		courseNodeAssessmentDao.updateCourseNodeAssessment(nodeAssessment);
+		
+		// node log
+		UserNodeAuditManager am = course.getCourseEnvironment().getAuditManager();
+		am.appendToUserNodeLog(courseNode, identity, assessedIdentity, "COMMENT set to: " + comment);
+
+		// notify about changes
+		AssessmentChangedEvent ace = new AssessmentChangedEvent(AssessmentChangedEvent.TYPE_USER_COMMENT_CHANGED, assessedIdentity);
+		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(ace, course);
+
+		// user activity logging
+		ThreadLocalUserActivityLogger.log(AssessmentLoggingAction.ASSESSMENT_USERCOMMENT_UPDATED, 
+				getClass(), 
+				LoggingResourceable.wrap(assessedIdentity), 
+				LoggingResourceable.wrapNonOlatResource(StringResourceableType.qtiUserComment, "", StringHelper.stripLineBreaks(comment)));	
+	}
+
+	@Override
+	public void saveNodeCoachComment(CourseNode courseNode, Identity assessedIdentity, String comment) {
+		ICourse course = CourseFactory.loadCourse(courseEntry.getOlatResource());
+		
+		AssessmentEntry nodeAssessment = getOrCreate(assessedIdentity, courseNode);
+		nodeAssessment.setCoachComment(comment);
+		courseNodeAssessmentDao.updateCourseNodeAssessment(nodeAssessment);
+		
+		// notify about changes
+		AssessmentChangedEvent ace = new AssessmentChangedEvent(AssessmentChangedEvent.TYPE_COACH_COMMENT_CHANGED, assessedIdentity);
+		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(ace, course);
+
+		// user activity logging
+		ThreadLocalUserActivityLogger.log(AssessmentLoggingAction.ASSESSMENT_COACHCOMMENT_UPDATED, 
+				getClass(), 
+				LoggingResourceable.wrap(assessedIdentity), 
+				LoggingResourceable.wrapNonOlatResource(StringResourceableType.qtiCoachComment, "", StringHelper.stripLineBreaks(comment)));	
+	}
+
+	@Override
+	public void incrementNodeAttempts(CourseNode courseNode, Identity assessedIdentity, UserCourseEnvironment userCourseEnv) {
+		ICourse course = CourseFactory.loadCourse(courseEntry.getOlatResource());
+		
+		AssessmentEntry nodeAssessment = getOrCreate(assessedIdentity, courseNode);
+		int attempts = nodeAssessment.getAttempts() == null ? 1 :nodeAssessment.getAttempts().intValue() + 1;
+		nodeAssessment.setAttempts(attempts);
+		courseNodeAssessmentDao.updateCourseNodeAssessment(nodeAssessment);
+		if(courseNode instanceof AssessableCourseNode) {
+			// Update users efficiency statement
+			efficiencyStatementManager.updateUserEfficiencyStatement(userCourseEnv);
+		}
+		
+		// notify about changes
+		AssessmentChangedEvent ace = new AssessmentChangedEvent(AssessmentChangedEvent.TYPE_ATTEMPTS_CHANGED, assessedIdentity);
+		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(ace, course);
+		
+		// user activity logging
+		ThreadLocalUserActivityLogger.log(AssessmentLoggingAction.ASSESSMENT_ATTEMPTS_UPDATED, 
+				getClass(), 
+				LoggingResourceable.wrap(assessedIdentity), 
+				LoggingResourceable.wrapNonOlatResource(StringResourceableType.qtiAttempts, "", String.valueOf(attempts)));
+	}
+
+	@Override
+	public void incrementNodeAttemptsInBackground(CourseNode courseNode, Identity assessedIdentity, UserCourseEnvironment userCourseEnv) {
+		ICourse course = CourseFactory.loadCourse(courseEntry.getOlatResource());
+		
+		AssessmentEntry nodeAssessment = getOrCreate(assessedIdentity, courseNode);
+		int attempts = nodeAssessment.getAttempts() == null ? 1 :nodeAssessment.getAttempts().intValue() + 1;
+		nodeAssessment.setAttempts(attempts);
+		courseNodeAssessmentDao.updateCourseNodeAssessment(nodeAssessment);
+		if(courseNode instanceof AssessableCourseNode) {
+			// Update users efficiency statement
+			efficiencyStatementManager.updateUserEfficiencyStatement(userCourseEnv);
+		}
+		
+		// notify about changes
+		AssessmentChangedEvent ace = new AssessmentChangedEvent(AssessmentChangedEvent.TYPE_ATTEMPTS_CHANGED, assessedIdentity);
+		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(ace, course);
+	}
+	
+	@Override
+	public void saveScoreEvaluation(CourseNode courseNode, Identity identity, Identity assessedIdentity,
+			ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnv,
+			boolean incrementUserAttempts) {
+		ICourse course = CourseFactory.loadCourse(courseEntry.getOlatResource());
+		
+		Float score = scoreEvaluation.getScore();
+		Boolean passed = scoreEvaluation.getPassed();
+		Long assessmentId = scoreEvaluation.getAssessmentID();
+
+		AssessmentEntry nodeAssessment = getOrCreate(assessedIdentity, courseNode);
+		if(score == null) {
+			nodeAssessment.setScore(null);
+		} else {
+			nodeAssessment.setScore(new BigDecimal(Float.toString(score)));
+		}
+		nodeAssessment.setPassed(passed);
+		nodeAssessment.setFullyAssessed(scoreEvaluation.getFullyAssessed());
+		nodeAssessment.setAssessmentId(assessmentId);
+		if(incrementUserAttempts) {
+			int attempts = nodeAssessment.getAttempts() == null ? 1 :nodeAssessment.getAttempts().intValue() + 1;
+			nodeAssessment.setAttempts(attempts);
+		}
+		nodeAssessment = courseNodeAssessmentDao.updateCourseNodeAssessment(nodeAssessment);
+		
+		
+		if(courseNode instanceof AssessableCourseNode) {
+			// Update users efficiency statement
+			efficiencyStatementManager.updateUserEfficiencyStatement(userCourseEnv);
+		}
+		
+		if(passed != null && passed.booleanValue() && course.getCourseConfig().isAutomaticCertificationEnabled()) {
+			if(certificatesManager.isRecertificationAllowed(assessedIdentity, courseEntry)) {
+				CertificateTemplate template = null;
+				Long templateId = course.getCourseConfig().getCertificateTemplate();
+				if(templateId != null) {
+					template = certificatesManager.getTemplateById(templateId);
+				}
+				CertificateInfos certificateInfos = new CertificateInfos(assessedIdentity, score, passed);
+				MailerResult result = new MailerResult();
+				certificatesManager.generateCertificate(certificateInfos, courseEntry, template, result);
+			}
+		}
+	}
+
+	@Override
+	public Float getNodeScore(CourseNode courseNode, Identity identity) {
+		if (courseNode == null) {
+			return FLOAT_ZERO; // return default value
+		}
+		
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.loadAssessmentEntry(identity, courseEntry, courseNode.getIdent());	
+		if(nodeAssessment != null && nodeAssessment.getScore() != null) {
+			return nodeAssessment.getScore().floatValue();
+		}
+		return FLOAT_ZERO;
+	}
+
+	@Override
+	public String getNodeComment(CourseNode courseNode, Identity identity) {
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.loadAssessmentEntry(identity, courseEntry, courseNode.getIdent());	
+		return nodeAssessment == null ? null : nodeAssessment.getComment();
+	}
+
+	@Override
+	public String getNodeCoachComment(CourseNode courseNode, Identity identity) {
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.loadAssessmentEntry(identity, courseEntry, courseNode.getIdent());	
+		return nodeAssessment == null ? null : nodeAssessment.getCoachComment();
+	}
+
+	@Override
+	public Boolean getNodePassed(CourseNode courseNode, Identity identity) {
+		if (courseNode == null) {
+			return Boolean.FALSE; // return default value
+		}
+		
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.loadAssessmentEntry(identity, courseEntry, courseNode.getIdent());	
+		return nodeAssessment == null ? null : nodeAssessment.getPassed();
+	}
+
+	@Override
+	public Integer getNodeAttempts(CourseNode courseNode, Identity identity) {
+		if(courseNode == null) return INTEGER_ZERO;
+		
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.loadAssessmentEntry(identity, courseEntry, courseNode.getIdent());	
+		return nodeAssessment == null ? INTEGER_ZERO : nodeAssessment.getAttempts();
+	}
+
+	@Override
+	public Long getAssessmentID(CourseNode courseNode, Identity identity) {
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.loadAssessmentEntry(identity, courseEntry, courseNode.getIdent());	
+		return nodeAssessment == null ? null : nodeAssessment.getAssessmentId();
+	}
+
+	@Override
+	public Date getScoreLastModifiedDate(CourseNode courseNode, Identity identity) {
+		if(courseNode == null) return null;
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.loadAssessmentEntry(identity, courseEntry, courseNode.getIdent());
+		return nodeAssessment == null ? null : nodeAssessment.getLastModified();
+	}
+
+	@Override
+	public Boolean getNodeFullyAssessed(CourseNode courseNode, Identity identity) {
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.loadAssessmentEntry(identity, courseEntry, courseNode.getIdent());	
+		return nodeAssessment == null ? null : nodeAssessment.getFullyAssessed();
+	}
+	
+	@Override
+	public OLATResourceable createOLATResourceableForLocking(Identity assessedIdentity) {
+		return OresHelper.createOLATResourceableInstance("AssessmentManager::Identity", assessedIdentity.getKey());
+	}
+	
+	@Override
+	public void registerForAssessmentChangeEvents(GenericEventListener gel, Identity identity) {
+		CoordinatorManager.getInstance().getCoordinator().getEventBus().registerFor(gel, identity, courseEntry.getOlatResource());
+	}
+
+	@Override
+	public void deregisterFromAssessmentChangeEvents(GenericEventListener gel) {
+		CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(gel, courseEntry.getOlatResource());
+	}
+	
+	@Override
+	public void preloadCache(Identity identity) {
+		// 
+	}
+
+	@Override
+	public void preloadCache(List<Identity> identities) {
+		//
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/model/AssessedIdentityWithCertificate.java b/src/main/java/org/olat/course/assessment/model/AssessedIdentityWithCertificate.java
new file mode 100644
index 0000000000000000000000000000000000000000..f85bbb43f571ecfd6e617e18428ae2fd4803dbf8
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/model/AssessedIdentityWithCertificate.java
@@ -0,0 +1,56 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.model;
+
+import org.olat.core.id.Identity;
+import org.olat.course.certificate.CertificateLight;
+
+/**
+ * 
+ * Initial date: 21.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class AssessedIdentityWithCertificate {
+	
+	private Identity identity;
+	private CertificateLight certificate;
+	
+	public AssessedIdentityWithCertificate() {
+		//
+	}
+	
+	public AssessedIdentityWithCertificate(Identity identity, CertificateLight certificate) {
+		this.identity = identity;
+		this.certificate = certificate;
+	}
+	
+	public Identity getIdentity() {
+		return identity;
+	}
+	
+	public void setIdentity(Identity identity) {
+		this.identity = identity;
+	}
+	
+	public CertificateLight getCertificate() {
+		return certificate;
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/model/SearchAssessedIdentityParams.java b/src/main/java/org/olat/course/assessment/model/SearchAssessedIdentityParams.java
new file mode 100644
index 0000000000000000000000000000000000000000..3370dd4cba1dc3a819f14e7cda076918896797be
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/model/SearchAssessedIdentityParams.java
@@ -0,0 +1,66 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.model;
+
+import java.util.List;
+
+import org.olat.group.BusinessGroupRef;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * Initial date: 21.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class SearchAssessedIdentityParams {
+	
+	private final RepositoryEntry courseEntry;
+	private boolean withCertificates;
+	private List<? extends BusinessGroupRef> businessGroups;
+	
+	public SearchAssessedIdentityParams(RepositoryEntry courseEntry) {
+		this.courseEntry = courseEntry;
+	}
+	
+	public RepositoryEntry getCourseEntry() {
+		return courseEntry;
+	}
+	
+	
+	public List<? extends BusinessGroupRef> getBusinessGroups() {
+		return businessGroups;
+	}
+
+	public void setBusinessGroups(List<? extends BusinessGroupRef> businessGroups) {
+		this.businessGroups = businessGroups;
+	}
+
+	public boolean isWithCertificates() {
+		return withCertificates;
+	}
+	
+	public void setWithCertificates(boolean withCertificates) {
+		this.withCertificates = withCertificates;
+	}
+	
+	
+
+}
diff --git a/src/main/java/org/olat/course/assessment/ui/AssessmentModeAdminController.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeAdminController.java
similarity index 97%
rename from src/main/java/org/olat/course/assessment/ui/AssessmentModeAdminController.java
rename to src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeAdminController.java
index 66f61723515463e6cdf3dcc1c259ef64a5ccbd36..1e6f6a4f10efc5afc210906698465bbf5c505081 100644
--- a/src/main/java/org/olat/course/assessment/ui/AssessmentModeAdminController.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeAdminController.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
diff --git a/src/main/java/org/olat/course/assessment/ui/AssessmentModeAdminListController.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeAdminListController.java
similarity index 96%
rename from src/main/java/org/olat/course/assessment/ui/AssessmentModeAdminListController.java
rename to src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeAdminListController.java
index 66b4b0534c8f1ebc5af645dd9e9c4319bbb15a19..20cd083d368a7b8826b9142a7e7590812a308620 100644
--- a/src/main/java/org/olat/course/assessment/ui/AssessmentModeAdminListController.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeAdminListController.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import java.util.List;
 
@@ -38,7 +38,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
@@ -48,7 +47,7 @@ import org.olat.course.assessment.AssessmentMode;
 import org.olat.course.assessment.AssessmentModeCoordinationService;
 import org.olat.course.assessment.AssessmentModeManager;
 import org.olat.course.assessment.model.SearchAssessmentModeParams;
-import org.olat.course.assessment.ui.AssessmentModeListModel.Cols;
+import org.olat.course.assessment.ui.mode.AssessmentModeListModel.Cols;
 import org.olat.repository.RepositoryEntry;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -105,7 +104,7 @@ public class AssessmentModeAdminListController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.status.i18nKey(), Cols.status.ordinal(),
 				true, Cols.status.name(), new ModeStatusCellRenderer()));
 		FlexiCellRenderer renderer = new StaticFlexiCellRenderer("select", new TextFlexiCellRenderer());
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.course.i18nKey(), Cols.course.ordinal(), "select",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.course.i18nKey(), Cols.course.ordinal(), "select",
 				true, Cols.course.name(), renderer));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.externalId.i18nKey(), Cols.externalId.ordinal(), true, Cols.externalId.name()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.externalRef.i18nKey(), Cols.externalRef.ordinal(), true, Cols.externalRef.name()));
diff --git a/src/main/java/org/olat/course/assessment/ui/AssessmentModeAdminSettingsController.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeAdminSettingsController.java
similarity index 98%
rename from src/main/java/org/olat/course/assessment/ui/AssessmentModeAdminSettingsController.java
rename to src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeAdminSettingsController.java
index 7b604ae5501a6af2ed849c040ed836a622bef815..3ff922c4b17447aee9c45f217e3ee6efb9201135 100644
--- a/src/main/java/org/olat/course/assessment/ui/AssessmentModeAdminSettingsController.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeAdminSettingsController.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
diff --git a/src/main/java/org/olat/course/assessment/ui/AssessmentModeEditController.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java
similarity index 99%
rename from src/main/java/org/olat/course/assessment/ui/AssessmentModeEditController.java
rename to src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java
index a6f79530026ed821db3946802a85e8d9c7367717..c04e9e9ad1aa3f90e951c2fc3b1567a8c1f6ae1c 100644
--- a/src/main/java/org/olat/course/assessment/ui/AssessmentModeEditController.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import java.util.ArrayList;
 import java.util.Date;
diff --git a/src/main/java/org/olat/course/assessment/ui/AssessmentModeGuardController.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeGuardController.java
similarity index 99%
rename from src/main/java/org/olat/course/assessment/ui/AssessmentModeGuardController.java
rename to src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeGuardController.java
index 992f391b5f3740aa6b42093e6d19d4d18fec1c3e..bb6bba6169e974c14862fb19c1888382e75bb6d6 100644
--- a/src/main/java/org/olat/course/assessment/ui/AssessmentModeGuardController.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeGuardController.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import java.util.ArrayList;
 import java.util.Date;
diff --git a/src/main/java/org/olat/course/assessment/ui/AssessmentModeListController.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListController.java
similarity index 96%
rename from src/main/java/org/olat/course/assessment/ui/AssessmentModeListController.java
rename to src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListController.java
index 42cef7938f59f8698bce6efd3ff7f4c6887f629a..67083d899b53ba0e6b7f8611f5d09e5e27e201ec 100644
--- a/src/main/java/org/olat/course/assessment/ui/AssessmentModeListController.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListController.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -37,7 +37,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.stack.PopEvent;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
@@ -55,7 +54,7 @@ import org.olat.course.assessment.AssessmentModeCoordinationService;
 import org.olat.course.assessment.AssessmentModeManager;
 import org.olat.course.assessment.AssessmentModeNotificationEvent;
 import org.olat.course.assessment.model.TransientAssessmentMode;
-import org.olat.course.assessment.ui.AssessmentModeListModel.Cols;
+import org.olat.course.assessment.ui.mode.AssessmentModeListModel.Cols;
 import org.olat.repository.RepositoryEntry;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -127,11 +126,11 @@ public class AssessmentModeListController extends FormBasicController implements
 				true, Cols.followupTime.name(), new TimeCellRenderer(getTranslator())));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.target.i18nKey(), Cols.target.ordinal(),
 				true, Cols.target.name(), new TargetAudienceCellRenderer(getTranslator())));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("start", Cols.start.ordinal(), "start",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("start", Cols.start.ordinal(), "start",
 				new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("start"), "start"), null)));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("stop", Cols.stop.ordinal(), "stop",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("stop", Cols.stop.ordinal(), "stop",
 				new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("stop"), "stop"), null)));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("edit", translate("edit"), "edit"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate("edit"), "edit"));
 		
 		model = new AssessmentModeListModel(columnsModel, getTranslator(), assessmentModeCoordinationService);
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/course/assessment/ui/AssessmentModeListModel.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListModel.java
similarity index 99%
rename from src/main/java/org/olat/course/assessment/ui/AssessmentModeListModel.java
rename to src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListModel.java
index b6fe0b6be18b1eb8360682dd5ccb387074ec2fda..4399978e62e767e9cc50876edba16e0b6ed75925 100644
--- a/src/main/java/org/olat/course/assessment/ui/AssessmentModeListModel.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListModel.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/main/java/org/olat/course/assessment/ui/AssessmentModeListModelSort.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListModelSort.java
similarity index 95%
rename from src/main/java/org/olat/course/assessment/ui/AssessmentModeListModelSort.java
rename to src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListModelSort.java
index 1e30ade2a26e2c583f2a5f4ca20ce4b7884f4b2e..52b0de2ddfd04dd54facb59901cd18712bad54c0 100644
--- a/src/main/java/org/olat/course/assessment/ui/AssessmentModeListModelSort.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListModelSort.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import java.util.Collections;
 import java.util.Comparator;
@@ -29,7 +29,7 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFl
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
 import org.olat.course.assessment.AssessmentMode;
 import org.olat.course.assessment.AssessmentMode.Status;
-import org.olat.course.assessment.ui.AssessmentModeListModel.Cols;
+import org.olat.course.assessment.ui.mode.AssessmentModeListModel.Cols;
 
 /**
  * 
diff --git a/src/main/java/org/olat/course/assessment/ui/ChooseAssessmentModeEvent.java b/src/main/java/org/olat/course/assessment/ui/mode/ChooseAssessmentModeEvent.java
similarity index 97%
rename from src/main/java/org/olat/course/assessment/ui/ChooseAssessmentModeEvent.java
rename to src/main/java/org/olat/course/assessment/ui/mode/ChooseAssessmentModeEvent.java
index bc39d2bf801b87d49f5804cee91df794981bda76..da2af55f78c4b812fd49518a3ec2a2f12ebe7b07 100644
--- a/src/main/java/org/olat/course/assessment/ui/ChooseAssessmentModeEvent.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/ChooseAssessmentModeEvent.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import org.olat.core.gui.control.Event;
 import org.olat.course.assessment.model.TransientAssessmentMode;
diff --git a/src/main/java/org/olat/course/assessment/ui/ChooseElementsController.java b/src/main/java/org/olat/course/assessment/ui/mode/ChooseElementsController.java
similarity index 98%
rename from src/main/java/org/olat/course/assessment/ui/ChooseElementsController.java
rename to src/main/java/org/olat/course/assessment/ui/mode/ChooseElementsController.java
index 882f4cbe052b341cc94f88b9926449b6842bd388..52426a072469420d839d82f8765894ccb93d788e 100644
--- a/src/main/java/org/olat/course/assessment/ui/ChooseElementsController.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/ChooseElementsController.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/main/java/org/olat/course/assessment/ui/ChooseStartElementController.java b/src/main/java/org/olat/course/assessment/ui/mode/ChooseStartElementController.java
similarity index 98%
rename from src/main/java/org/olat/course/assessment/ui/ChooseStartElementController.java
rename to src/main/java/org/olat/course/assessment/ui/mode/ChooseStartElementController.java
index 7391a04c21afeedbdf4f102000070c3cadc2de47..9cfaacbe0c008185a6b33f08c555f9f5d1c6acc7 100644
--- a/src/main/java/org/olat/course/assessment/ui/ChooseStartElementController.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/ChooseStartElementController.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/main/java/org/olat/course/assessment/ui/CourseNodeSelectionTreeModel.java b/src/main/java/org/olat/course/assessment/ui/mode/CourseNodeSelectionTreeModel.java
similarity index 97%
rename from src/main/java/org/olat/course/assessment/ui/CourseNodeSelectionTreeModel.java
rename to src/main/java/org/olat/course/assessment/ui/mode/CourseNodeSelectionTreeModel.java
index b3ce1b3f80e87de76f2cfa4e0e8516fa57869e4a..23bd46203547959425e89b8f36477ebe3c1fc924 100644
--- a/src/main/java/org/olat/course/assessment/ui/CourseNodeSelectionTreeModel.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/CourseNodeSelectionTreeModel.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import org.olat.core.gui.components.tree.GenericTreeModel;
 import org.olat.core.gui.components.tree.GenericTreeNode;
diff --git a/src/main/java/org/olat/course/assessment/ui/ModeStatusCellRenderer.java b/src/main/java/org/olat/course/assessment/ui/mode/ModeStatusCellRenderer.java
similarity index 98%
rename from src/main/java/org/olat/course/assessment/ui/ModeStatusCellRenderer.java
rename to src/main/java/org/olat/course/assessment/ui/mode/ModeStatusCellRenderer.java
index fe5f1ce4ade81f1ee96ceb9652568b0707792241..b0b2943106eb83a59fd1fbe8d11dd367f776b4df 100644
--- a/src/main/java/org/olat/course/assessment/ui/ModeStatusCellRenderer.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/ModeStatusCellRenderer.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import java.util.List;
 
diff --git a/src/main/java/org/olat/course/assessment/ui/TargetAudienceCellRenderer.java b/src/main/java/org/olat/course/assessment/ui/mode/TargetAudienceCellRenderer.java
similarity index 97%
rename from src/main/java/org/olat/course/assessment/ui/TargetAudienceCellRenderer.java
rename to src/main/java/org/olat/course/assessment/ui/mode/TargetAudienceCellRenderer.java
index 91e970a14b9e13e81a83797d322a15beb4b859d3..6b535c3b7b3ebe6a8cf325d619f42711956f4ee7 100644
--- a/src/main/java/org/olat/course/assessment/ui/TargetAudienceCellRenderer.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/TargetAudienceCellRenderer.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
diff --git a/src/main/java/org/olat/course/assessment/ui/TimeCellRenderer.java b/src/main/java/org/olat/course/assessment/ui/mode/TimeCellRenderer.java
similarity index 97%
rename from src/main/java/org/olat/course/assessment/ui/TimeCellRenderer.java
rename to src/main/java/org/olat/course/assessment/ui/mode/TimeCellRenderer.java
index d14e8195632262c56325094458787697b1fb9b82..6fedbdce2bc5a794010363735809f2f618a8db30 100644
--- a/src/main/java/org/olat/course/assessment/ui/TimeCellRenderer.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/TimeCellRenderer.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment.ui;
+package org.olat.course.assessment.ui.mode;
 
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
diff --git a/src/main/java/org/olat/course/assessment/ui/_content/admin.html b/src/main/java/org/olat/course/assessment/ui/mode/_content/admin.html
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_content/admin.html
rename to src/main/java/org/olat/course/assessment/ui/mode/_content/admin.html
diff --git a/src/main/java/org/olat/course/assessment/ui/_content/admin_search.html b/src/main/java/org/olat/course/assessment/ui/mode/_content/admin_search.html
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_content/admin_search.html
rename to src/main/java/org/olat/course/assessment/ui/mode/_content/admin_search.html
diff --git a/src/main/java/org/olat/course/assessment/ui/_content/choose_elements.html b/src/main/java/org/olat/course/assessment/ui/mode/_content/choose_elements.html
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_content/choose_elements.html
rename to src/main/java/org/olat/course/assessment/ui/mode/_content/choose_elements.html
diff --git a/src/main/java/org/olat/course/assessment/ui/_content/choose_groups.html b/src/main/java/org/olat/course/assessment/ui/mode/_content/choose_groups.html
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_content/choose_groups.html
rename to src/main/java/org/olat/course/assessment/ui/mode/_content/choose_groups.html
diff --git a/src/main/java/org/olat/course/assessment/ui/_content/choose_mode.html b/src/main/java/org/olat/course/assessment/ui/mode/_content/choose_mode.html
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_content/choose_mode.html
rename to src/main/java/org/olat/course/assessment/ui/mode/_content/choose_mode.html
diff --git a/src/main/java/org/olat/course/assessment/ui/_content/course_element.html b/src/main/java/org/olat/course/assessment/ui/mode/_content/course_element.html
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_content/course_element.html
rename to src/main/java/org/olat/course/assessment/ui/mode/_content/course_element.html
diff --git a/src/main/java/org/olat/course/assessment/ui/_content/course_elements.html b/src/main/java/org/olat/course/assessment/ui/mode/_content/course_elements.html
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_content/course_elements.html
rename to src/main/java/org/olat/course/assessment/ui/mode/_content/course_elements.html
diff --git a/src/main/java/org/olat/course/assessment/ui/_content/mode_list.html b/src/main/java/org/olat/course/assessment/ui/mode/_content/mode_list.html
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_content/mode_list.html
rename to src/main/java/org/olat/course/assessment/ui/mode/_content/mode_list.html
diff --git a/src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_de.properties
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_de.properties
rename to src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_de.properties
diff --git a/src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_en.properties
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_en.properties
rename to src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_en.properties
diff --git a/src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_fr.properties
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_fr.properties
rename to src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_fr.properties
diff --git a/src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_pt_BR.properties
similarity index 100%
rename from src/main/java/org/olat/course/assessment/ui/_i18n/LocalStrings_pt_BR.properties
rename to src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_pt_BR.properties
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityController.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityController.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1dee132bc920aef8cc5866159ce2f8ff2dd0f39
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityController.java
@@ -0,0 +1,59 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.ui.tool;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+
+/**
+ * 
+ * Initial date: 22.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class AssessedIdentityController extends FormBasicController {
+	
+	public AssessedIdentityController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		//
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+	
+	
+
+}
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListController.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..4fbc651345f289c6d228950c025af73ce059b8a6
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListController.java
@@ -0,0 +1,281 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.ui.tool;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.basesecurity.BaseSecurityModule;
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnDef;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.core.util.Util;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.event.GenericEventListener;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.assessment.AssessedIdentitiesTableDataModel;
+import org.olat.course.assessment.AssessmentMainController;
+import org.olat.course.assessment.AssessmentToolManager;
+import org.olat.course.assessment.IAssessmentCallback;
+import org.olat.course.assessment.IdentityAssessmentEditController;
+import org.olat.course.assessment.model.SearchAssessedIdentityParams;
+import org.olat.course.certificate.CertificateEvent;
+import org.olat.course.certificate.CertificateLight;
+import org.olat.course.certificate.CertificatesManager;
+import org.olat.course.certificate.ui.DownloadCertificateCellRenderer;
+import org.olat.repository.RepositoryEntry;
+import org.olat.user.UserManager;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 21.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class AssessedIdentityListController extends FormBasicController implements GenericEventListener {
+	
+	public static final int USER_PROPS_OFFSET = 500;
+	public static final String usageIdentifyer = AssessedIdentitiesTableDataModel.usageIdentifyer;
+
+	private FlexiTableElement tableEl;
+	private AssessedUserTableModel usersTableModel;
+	private final List<UserPropertyHandler> userPropertyHandlers;
+	private final TooledStackedPanel stackPanel;
+
+	private RepositoryEntry courseEntry;
+	private final boolean isAdministrativeUser;
+	private final IAssessmentCallback assessmentCallback;
+	
+	@Autowired
+	private UserManager userManager;
+	@Autowired
+	private BaseSecurity securityManager;
+	@Autowired
+	private BaseSecurityModule securityModule;
+	@Autowired
+	private CertificatesManager certificatesManager;
+	@Autowired
+	private AssessmentToolManager assessmentToolManager;
+
+	
+	public AssessedIdentityListController(UserRequest ureq, WindowControl wControl,
+			TooledStackedPanel stackPanel, RepositoryEntry courseEntry, IAssessmentCallback assessmentCallback) {
+		super(ureq, wControl, "identities");
+		setTranslator(Util.createPackageTranslator(AssessmentMainController.class, getLocale(), getTranslator()));
+		setTranslator(userManager.getPropertyHandlerTranslator(getTranslator()));
+
+		this.stackPanel = stackPanel;
+		this.courseEntry = courseEntry;
+		this.assessmentCallback = assessmentCallback;
+		isAdministrativeUser = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles());
+		userPropertyHandlers = UserManager.getInstance().getUserPropertyHandlersFor(usageIdentifyer, isAdministrativeUser);
+		
+		initForm(ureq);
+		updateModel();
+		
+		// Register for assessment changed events
+		CoordinatorManager.getInstance().getCoordinator().getEventBus()
+				.registerFor(this, getIdentity(), CertificatesManager.ORES_CERTIFICATE_EVENT);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		//add the table
+		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(UserCols.username, "select"));
+		
+		int colIndex = USER_PROPS_OFFSET;
+		List<UserPropertyHandler> userPropertyHandlers = userManager.getUserPropertyHandlersFor(usageIdentifyer, isAdministrativeUser);
+		for (int i = 0; i < userPropertyHandlers.size(); i++) {
+			UserPropertyHandler userPropertyHandler	= userPropertyHandlers.get(i);
+			boolean visible = UserManager.getInstance().isMandatoryUserProperty(usageIdentifyer , userPropertyHandler);
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex++, "select", false, null));
+		}
+		
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(UserCols.certificate, new DownloadCertificateCellRenderer()));
+
+		usersTableModel = new AssessedUserTableModel(columnsModel); 
+		tableEl = uifactory.addTableElement(getWindowControl(), "identities", usersTableModel, getTranslator(), formLayout);
+		tableEl.setExportEnabled(true);
+	}
+	
+	private void updateModel() {
+		SearchAssessedIdentityParams params = new SearchAssessedIdentityParams(courseEntry);
+		params.setWithCertificates(true);
+		List<Identity> assessedIdentities = assessmentToolManager.getAssessedIdentityWithCertificates(params);
+		List<AssessedIdentityRow> rows = new ArrayList<>(assessedIdentities.size());
+		for(Identity assessedIdentity:assessedIdentities) {
+			rows.add(new AssessedIdentityRow(assessedIdentity, userPropertyHandlers, getLocale()));
+		}
+		usersTableModel.setObjects(rows);
+		
+		ConcurrentMap<Long, CertificateLight> certificates =  new ConcurrentHashMap<>();
+		List<CertificateLight> certificateList = certificatesManager.getLastCertificates(courseEntry.getOlatResource());
+		for(CertificateLight certificate:certificateList) {
+			CertificateLight currentCertificate = certificates.get(certificate.getIdentityKey());
+			if(currentCertificate == null || currentCertificate.getCreationDate().before(certificate.getCreationDate())) {
+				certificates.put(certificate.getIdentityKey(), certificate);
+			}
+		}
+		usersTableModel.setCertificates(certificates);
+	}
+	
+	private void updateCertificate(Long certificateKey) {
+		CertificateLight certificate = certificatesManager.getCertificateLightById(certificateKey);
+		usersTableModel.putCertificate(certificate);
+		tableEl.getComponent().setDirty(true);
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	@Override
+	public void event(Event event) {
+		if(event instanceof CertificateEvent) {
+			CertificateEvent ce = (CertificateEvent)event;
+			if(courseEntry.getOlatResource().getKey().equals(ce.getResourceKey())) {
+				updateCertificate(ce.getCertificateKey());
+			}
+		}
+	}
+	
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+	
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(tableEl == source) {
+			if(event instanceof SelectionEvent) {
+				SelectionEvent se = (SelectionEvent)event;
+				String cmd = se.getCommand();
+				AssessedIdentityRow selectedRow = usersTableModel.getObject(se.getIndex());
+				if("select".equals(cmd)) {
+					doSelectUser(ureq, selectedRow);
+				}
+			}
+		} else if(source instanceof FormLink) {
+			FormLink link = (FormLink)source;
+			if("download-cert".equals(link.getCmd())) {
+				
+			}
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+	
+	private void doSelectUser(UserRequest ureq, AssessedIdentityRow row) {
+		ICourse course = CourseFactory.loadCourse(courseEntry.getOlatResource());
+		Identity assessedIdentity = securityManager.loadIdentityByKey(row.getIdentityKey());
+		IdentityAssessmentEditController userController = new IdentityAssessmentEditController(getWindowControl(), ureq,
+				stackPanel, assessedIdentity, course, true, false, true);
+		listenTo(userController);
+		String fullname = userManager.getUserDisplayName(assessedIdentity);
+		stackPanel.pushController(fullname, userController);
+	}
+
+	public static class AssessedUserTableModel extends DefaultFlexiTableDataModel<AssessedIdentityRow> implements SortableFlexiTableDataModel<AssessedIdentityRow> {
+
+		private ConcurrentMap<Long, CertificateLight> certificates;
+
+		public AssessedUserTableModel(FlexiTableColumnModel columnModel) {
+			super(columnModel);
+		}
+		
+		public void setCertificates(ConcurrentMap<Long, CertificateLight> certificates) {
+			this.certificates = certificates;
+		}
+		
+		public void putCertificate(CertificateLight certificate) {
+			if(certificates != null) {
+				certificates.put(certificate.getIdentityKey(), certificate);
+			}
+		}
+		
+		@Override
+		public void sort(SortKey sortKey) {
+			//
+		}
+		
+		@Override
+		public Object getValueAt(int row, int col) {
+			AssessedIdentityRow identityRow = getObject(row);
+			return getValueAt(identityRow, col);
+		}
+
+		@Override
+		public Object getValueAt(AssessedIdentityRow row, int col) {
+			if(col >= 0 && col < UserCols.values().length) {
+				switch(UserCols.values()[col]) {
+					case username: return row.getIdentityName();
+					case certificate: return certificates.get(row.getIdentityKey());
+				}
+			}
+			int propPos = col - USER_PROPS_OFFSET;
+			return row.getIdentityProp(propPos);
+		}
+
+		@Override
+		public DefaultFlexiTableDataModel<AssessedIdentityRow> createCopyWithEmptyList() {
+			return new AssessedUserTableModel(getTableColumnModel());
+		}
+	}
+
+	public enum UserCols implements FlexiColumnDef {
+		
+		username("table.header.name"),
+		certificate("table.header.certificate");
+		
+		private final String i18nKey;
+		
+		private UserCols(String i18nKey) {
+			this.i18nKey = i18nKey;
+		}
+		
+		public String i18nHeaderKey() {
+			return i18nKey;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityRow.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..ea7aa45ea18a418f06e204f460d6fc29dd0b2394
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityRow.java
@@ -0,0 +1,44 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.ui.tool;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.id.Identity;
+import org.olat.user.UserPropertiesRow;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
+
+/**
+ * 
+ * Initial date: 21.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class AssessedIdentityRow extends UserPropertiesRow {
+	
+	
+	public AssessedIdentityRow(Identity identity, List<UserPropertyHandler> userPropertyHandlers, Locale locale) {
+		super(identity, userPropertyHandlers, locale);
+	}
+
+
+
+}
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentOverviewController.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentOverviewController.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a011297e6a61887f1d359137592aa4ef406d30d
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentOverviewController.java
@@ -0,0 +1,173 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.ui.tool;
+
+import java.util.List;
+
+import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.panel.Panel;
+import org.olat.core.gui.components.stack.TooledStackedPanel;
+import org.olat.core.gui.components.tree.GenericTreeModel;
+import org.olat.core.gui.components.tree.GenericTreeNode;
+import org.olat.core.gui.components.tree.MenuTree;
+import org.olat.core.gui.components.tree.TreeModel;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.MainLayoutBasicController;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.Util;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.assessment.AssessmentMainController;
+import org.olat.course.assessment.IAssessmentCallback;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * Initial date: 21.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class AssessmentOverviewController extends MainLayoutBasicController implements Activateable2 {
+	
+	private MenuTree menuTree;
+	private final Panel mainPanel;
+	private TooledStackedPanel stackPanel;
+	
+	private boolean hasAssessableNodes;
+	private RepositoryEntry courseEntry;
+	private IAssessmentCallback assessmentCallback;
+	
+	public AssessmentOverviewController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
+			RepositoryEntry courseEntry, IAssessmentCallback assessmentCallback) {
+		super(ureq, wControl);
+		setTranslator(Util.createPackageTranslator(AssessmentMainController.class, getLocale(), getTranslator()));
+		this.courseEntry = courseEntry;
+		this.stackPanel = stackPanel;
+		this.assessmentCallback = assessmentCallback;
+		
+		ICourse course = CourseFactory.loadCourse(courseEntry.getOlatResource());
+		
+		hasAssessableNodes = course.hasAssessableNodes();
+		boolean hasCertificates = course.getCourseConfig().isAutomaticCertificationEnabled()
+				|| course.getCourseConfig().isManualCertificationEnabled();
+		
+		mainPanel = new Panel("assessmentToolv2");
+		
+		// Navigation menu
+		menuTree = new MenuTree("menuTree");
+		TreeModel tm = buildTreeModel(hasAssessableNodes, hasCertificates);
+		menuTree.setTreeModel(tm);
+		menuTree.setSelectedNodeId(tm.getRootNode().getIdent());
+		menuTree.addListener(this);
+
+		LayoutMain3ColsController columLayoutCtr = new LayoutMain3ColsController(ureq, getWindowControl(), menuTree, mainPanel, "course" + course.getResourceableId());
+		listenTo(columLayoutCtr); // cleanup on dispose
+		putInitialPanel(columLayoutCtr.getInitialComponent());
+	}
+	
+	private TreeModel buildTreeModel(boolean assessableNodes, boolean certificate) {
+		GenericTreeNode root, gtn;
+
+		GenericTreeModel gtm = new GenericTreeModel();
+		root = new GenericTreeNode();
+		root.setTitle(translate("menu.index"));
+		root.setUserObject("index");
+		root.setAltText(translate("menu.index.alt"));
+		gtm.setRootNode(root);
+
+		// show real menu only when there are some assessable nodes
+		/*
+		if (assessableNodes) {
+			gtn = new GenericTreeNode();
+			gtn.setTitle(translate("menu.groupfocus"));
+			gtn.setUserObject("groups");
+			gtn.setAltText(translate("menu.groupfocus.alt"));
+			gtn.setCssClass("o_sel_assessment_tool_groups");
+			root.addChild(gtn);
+	
+			gtn = new GenericTreeNode();
+			gtn.setTitle(translate("menu.nodefocus"));
+			gtn.setUserObject("courseNodes");
+			gtn.setAltText(translate("menu.nodefocus.alt"));
+			gtn.setCssClass("o_sel_assessment_tool_nodes");
+			root.addChild(gtn);
+		}
+		*/
+		
+		if (assessableNodes || certificate) {
+			gtn = new GenericTreeNode();
+			gtn.setTitle(translate("menu.userfocus"));
+			gtn.setUserObject("users");
+			gtn.setAltText(translate("menu.userfocus.alt"));
+			gtn.setCssClass("o_sel_assessment_tool_users");
+			root.addChild(gtn);
+		}
+
+		return gtm;
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if (source == menuTree) {
+			if (event.getCommand().equals(MenuTree.COMMAND_TREENODE_CLICKED)) {
+				Object uo = menuTree.getSelectedNode().getUserObject();
+				if("groups".equals(uo)) {
+					doSelectGroupView();
+				} else if("courseNodes".equals(uo)) {
+					doSelectCourseNodesView();
+				} else if("users".equals(uo)) {
+					doSelectUsersView(ureq);
+				}
+			}
+		}
+	}
+	
+	private void doSelectGroupView() {
+		
+	}
+
+	private void doSelectCourseNodesView() {
+		
+	}
+	
+	private void doSelectUsersView(UserRequest ureq) {
+		AssessedIdentityListController listController = new AssessedIdentityListController(ureq, getWindowControl(), stackPanel,
+				courseEntry, assessmentCallback);
+		listenTo(listController);
+		mainPanel.setContent(listController.getInitialComponent());
+	}
+	
+
+}
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/_content/identities.html b/src/main/java/org/olat/course/assessment/ui/tool/_content/identities.html
new file mode 100644
index 0000000000000000000000000000000000000000..42a472edfd4b53b23f921ce1e1734d813c08e393
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/tool/_content/identities.html
@@ -0,0 +1 @@
+$r.render("identities")
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/_content/overview.html b/src/main/java/org/olat/course/assessment/ui/tool/_content/overview.html
new file mode 100644
index 0000000000000000000000000000000000000000..3b2634d5414ce45796a9da01b6f1fde618d9e34a
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/tool/_content/overview.html
@@ -0,0 +1 @@
+<h1>Hello</h1>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/assessment/ui/tool/_i18n/LocalStrings_de.properties
new file mode 100644
index 0000000000000000000000000000000000000000..88cd94609c457d55e0bd694399d70ada03acb762
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/tool/_i18n/LocalStrings_de.properties
@@ -0,0 +1 @@
+#Mon Mar 02 09:54:04 CET 2009
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/assessment/ui/tool/_i18n/LocalStrings_en.properties
new file mode 100644
index 0000000000000000000000000000000000000000..ec501f9f433fed1a8bde1ac9922be1c4d209298e
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/tool/_i18n/LocalStrings_en.properties
@@ -0,0 +1 @@
+#Fri Feb 06 10:03:07 CET 2015
diff --git a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java
index 99a377a4b56cb533aac4bbe9a73df2eaee6ec964..baac00e0fda18fafca2f679aa5fb41dda92831e0 100644
--- a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java
+++ b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.stack.BreadcrumbPanel;
 import org.olat.core.gui.components.stack.BreadcrumbPanelAware;
@@ -176,20 +175,20 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo
 		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.score.i18n(), Cols.score.ordinal()));
 		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.passed.i18n(), Cols.passed.ordinal(),
 				new PassedCellRenderer()));
-		tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.show",
+		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.show",
 				translate("table.header.show"), CMD_SHOW));
 		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.lastModified.i18n(), Cols.lastModified.ordinal()));
 		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.certificate.i18n(), Cols.certificate.ordinal(),
 				new DownloadCertificateCellRenderer(assessedIdentity)));
-		tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.launchcourse",
+		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.launchcourse",
 				translate("table.header.launchcourse"), CMD_LAUNCH_COURSE));
-		tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.delete",
+		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.delete",
 				translate("table.action.delete"), CMD_DELETE));
 		
 		//delete
 		EPArtefactHandler<?> artHandler = portfolioModule.getArtefactHandler(EfficiencyStatementArtefact.ARTEFACT_TYPE);
 		if(portfolioModule.isEnabled() && artHandler != null && artHandler.isEnabled() && assessedIdentity.equals(getIdentity())) {
-			tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.artefact",
+			tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.artefact",
 					Cols.efficiencyStatement.ordinal(), CMD_ARTEFACT,
 					new StaticFlexiCellRenderer(CMD_ARTEFACT, new AsArtefactCellRenderer())));
 		}
diff --git a/src/main/java/org/olat/course/certificate/ui/CertificatesAdminController.java b/src/main/java/org/olat/course/certificate/ui/CertificatesAdminController.java
index 526ba9ac2a70b07b1bec293730115651ebad1172..32fe7d4f8bd906227124c998dea055667c2ea5aa 100644
--- a/src/main/java/org/olat/course/certificate/ui/CertificatesAdminController.java
+++ b/src/main/java/org/olat/course/certificate/ui/CertificatesAdminController.java
@@ -33,7 +33,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFle
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -75,8 +74,8 @@ public class CertificatesAdminController extends FormBasicController {
 		
 		FlexiTableColumnModel tableColumnModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal()));
-		tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("replace", translate("replace"), "replace"));
-		tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", translate("delete"), "delete"));
+		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("replace", translate("replace"), "replace"));
+		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete"));
 		
 		tableModel = new TemplatesDataModel(tableColumnModel);
 		tableEl = uifactory.addTableElement(getWindowControl(), "templates", tableModel, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/course/certificate/ui/DownloadCertificateCellRenderer.java b/src/main/java/org/olat/course/certificate/ui/DownloadCertificateCellRenderer.java
index 03477dcebe1b034ec214262a86ba2aaec7afbf0c..09c89054f9ff300e5e25d368e32c35d155e9b3de 100644
--- a/src/main/java/org/olat/course/certificate/ui/DownloadCertificateCellRenderer.java
+++ b/src/main/java/org/olat/course/certificate/ui/DownloadCertificateCellRenderer.java
@@ -21,6 +21,8 @@ package org.olat.course.certificate.ui;
 
 import java.util.Locale;
 
+import org.olat.basesecurity.IdentityRef;
+import org.olat.basesecurity.model.IdentityRefImpl;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
@@ -71,15 +73,20 @@ public class DownloadCertificateCellRenderer implements CustomCellRenderer, Flex
 	public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source,
 			URLBuilder ubu, Translator translator) {
 		if(cellValue instanceof CertificateLight) {
-			render(target, (CertificateLight)cellValue, assessedIdentity, translator.getLocale());
+			CertificateLight certificate = (CertificateLight)cellValue;
+			if(assessedIdentity == null) {
+				IdentityRef idRef = new IdentityRefImpl(certificate.getIdentityKey());
+				render(target, certificate, idRef, translator.getLocale());
+			} else {
+				render(target, certificate, assessedIdentity, translator.getLocale());
+			}
 		} else if(cellValue instanceof CertificateLightPack) {
 			CertificateLightPack pack = (CertificateLightPack)cellValue;
 			render(target, pack.getCertificate(), pack.getIdentity(), translator.getLocale());	
 		}
 	}
 	
-	
-	private void render(StringOutput sb, CertificateLight certificate, Identity identity, Locale locale) {
+	private void render(StringOutput sb, CertificateLight certificate, IdentityRef identity, Locale locale) {
 		String name = Formatter.getInstance(locale).formatDate(certificate.getCreationDate());
 		if(CertificateStatus.pending.equals(certificate.getStatus())) {
 			sb.append("<span><i class='o_icon o_icon_pending o_icon-spin'> </i> ").append(name).append(".pdf").append("</span>");
@@ -101,7 +108,7 @@ public class DownloadCertificateCellRenderer implements CustomCellRenderer, Flex
 		return finalName + ".pdf";
 	}
 	
-	public static String getName(CertificateLight certificate, Identity identity) {
+	public static String getName(CertificateLight certificate, IdentityRef identity) {
 		StringBuilder sb = new StringBuilder(100);
 		String fullName = CoreSpringFactory.getImpl(UserManager.class).getUserDisplayName(identity);
 		String date = Formatter.formatShortDateFilesystem(certificate.getCreationDate());
@@ -110,7 +117,7 @@ public class DownloadCertificateCellRenderer implements CustomCellRenderer, Flex
 		return finalName + ".pdf";
 	}
 	
-	public static String getUrl(CertificateLight certificate, Identity identity) {
+	public static String getUrl(CertificateLight certificate, IdentityRef identity) {
 		StringBuilder sb = new StringBuilder(100);
 		sb.append(Settings.getServerContextPath()).append("/certificate/")
 		  .append(certificate.getUuid()).append("/").append(getName(certificate, identity));
diff --git a/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java b/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java
index f9215f4b81994fa06c9c788446ce039b87db5877..2d7f8bd09c8f562e1fbaef524c185990b15e6bdf 100644
--- a/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java
+++ b/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java
@@ -35,7 +35,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
@@ -119,7 +118,7 @@ public class CourseBusinessGroupListController extends AbstractBusinessGroupList
 		
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		//group name
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
 				true, Cols.name.name(), new StaticFlexiCellRenderer(TABLE_ACTION_LAUNCH, new BusinessGroupNameCellRenderer())));
 		//id and reference
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.key.i18n(), Cols.key.ordinal(), true, Cols.key.name()));
@@ -146,10 +145,10 @@ public class CourseBusinessGroupListController extends AbstractBusinessGroupList
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.accessTypes.i18n(), Cols.accessTypes.ordinal(),
 				true, Cols.accessTypes.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGAccessControlledCellRenderer()));
 
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.edit", translate("table.header.edit"), TABLE_ACTION_EDIT));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.edit", translate("table.header.edit"), TABLE_ACTION_EDIT));
 		
 		if(!managed) {
-			columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.remove", Cols.unlink.ordinal(), TABLE_ACTION_UNLINK,
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.remove", Cols.unlink.ordinal(), TABLE_ACTION_UNLINK,
 					new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("table.header.remove"), TABLE_ACTION_UNLINK), null)));
 		}
 		return columnsModel;
diff --git a/src/main/java/org/olat/course/nodes/MSCourseNode.java b/src/main/java/org/olat/course/nodes/MSCourseNode.java
index e9d698808d2ca14189fb71d345ce1b6523af914c..e106fde2c3a7f3801dd98085dc43a5bac309c331 100644
--- a/src/main/java/org/olat/course/nodes/MSCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/MSCourseNode.java
@@ -441,11 +441,9 @@ public class MSCourseNode extends AbstractAccessableCourseNode implements Assess
 		return tools;
 	}
 
-	/**
-	 * @see org.olat.course.nodes.AssessableCourseNode#getDetailsListView(org.olat.course.run.userview.UserCourseEnvironment)
-	 */
+	@Override
 	public String getDetailsListView(UserCourseEnvironment userCourseEnvironment) {
-		throw new OLATRuntimeException(MSCourseNode.class, "Details not available in MS nodes", null);
+		return null;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/course/nodes/STCourseNode.java b/src/main/java/org/olat/course/nodes/STCourseNode.java
index 1dd4cc8b9f4a5e893ca9f3fd868d4e299d12cfc7..af2cd168fb9dec595f27ae4a2d1b0caef8e8def4 100644
--- a/src/main/java/org/olat/course/nodes/STCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/STCourseNode.java
@@ -532,11 +532,9 @@ public class STCourseNode extends AbstractAccessableCourseNode implements Assess
 		throw new OLATRuntimeException(STCourseNode.class, "Details controler not available in ST nodes", null);
 	}
 
-	/**
-	 * @see org.olat.course.nodes.AssessableCourseNode#getDetailsListView(org.olat.course.run.userview.UserCourseEnvironment)
-	 */
+	@Override
 	public String getDetailsListView(UserCourseEnvironment userCourseEnvironment) {
-		throw new OLATRuntimeException(STCourseNode.class, "Details not available in ST nodes", null);
+		return null;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java
index b326bb7b12d19934998ef5fde66527e788c7271d..f32905a624d8eb882aa0e0d888c553ffd8f3e49b 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java
@@ -57,7 +57,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
@@ -214,7 +213,7 @@ public class CheckListAssessmentController extends FormBasicController implement
 				FlexiColumnModel col;
 				if(UserConstants.FIRSTNAME.equals(propName)
 						|| UserConstants.LASTNAME.equals(propName)) {
-					col = new StaticFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
+					col = new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
 							colIndex, userPropertyHandler.getName(), true, propName,
 							new StaticFlexiCellRenderer(userPropertyHandler.getName(), new TextFlexiCellRenderer()));
 				} else {
@@ -238,7 +237,7 @@ public class CheckListAssessmentController extends FormBasicController implement
 		if(withScore) {
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.totalPoints.i18nKey(), Cols.totalPoints.ordinal(), true, "points"));
 		}
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.edit.checkbox", translate("table.header.edit.checkbox"), "edit"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.edit.checkbox", translate("table.header.edit.checkbox"), "edit"));
 
 		List<CheckListAssessmentRow> datas = loadDatas();
 		model = new CheckListAssessmentDataModel(checkboxList, datas, columnsModel);
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListBoxListEditController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListBoxListEditController.java
index e7660d4c389e8e94fb384dba08c84c1c150368ea..77ad3ef1824d76a065ff8df987084996214b762c 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListBoxListEditController.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListBoxListEditController.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -125,12 +124,12 @@ public class CheckListBoxListEditController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(pointColModel);
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.release.i18nKey(), Cols.release.ordinal()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.file.i18nKey(), Cols.file.ordinal()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("edit", translate("edit"), "edit"));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("up", Cols.up.ordinal(), "up",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate("edit"), "edit"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("up", Cols.up.ordinal(), "up",
 				new BooleanCellRenderer(
 						new StaticFlexiCellRenderer("", "up", "o_icon o_icon-lg o_icon_move_up", translate("up")),
 						null)));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("down", Cols.down.ordinal(), "down",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("down", Cols.down.ordinal(), "down",
 				new BooleanCellRenderer(
 						new StaticFlexiCellRenderer("", "down", "o_icon o_icon-lg o_icon_move_down", translate("down")),
 						null)));
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java
index 48a780dfbfc59c76aa8fc3ad7848958e962dd83c..ff7a10886b2fd98f0e9cee82bca8f8d6f87d8828 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java
@@ -46,7 +46,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColum
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
@@ -150,7 +149,7 @@ public class CheckboxAssessmentController extends FormBasicController {
 				FlexiColumnModel col;
 				if(UserConstants.FIRSTNAME.equals(propName)
 						|| UserConstants.LASTNAME.equals(propName)) {
-					col = new StaticFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
+					col = new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
 							colIndex, userPropertyHandler.getName(), true, propName,
 							new StaticFlexiCellRenderer(userPropertyHandler.getName(), new TextFlexiCellRenderer()));
 				} else {
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckboxListStepController.java b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckboxListStepController.java
index d731f2bbcf317737636777ebfe294c0c5076e441..bbf52fc31d7359867ee100d217916d4542b0c60c 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckboxListStepController.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckboxListStepController.java
@@ -36,7 +36,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFle
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -99,7 +98,7 @@ public class CheckboxListStepController extends StepFormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.points.i18nKey(), Cols.points.ordinal()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.release.i18nKey(), Cols.release.ordinal()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.file.i18nKey(), Cols.file.ordinal()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("edit.checkbox", translate("edit.checkbox"), "edit"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit.checkbox", translate("edit.checkbox"), "edit"));
 
 		model = new CheckboxConfigDataModel(getTranslator(), columnsModel);
 		boxTable = uifactory.addTableElement(getWindowControl(), "checkbox-list", model, getTranslator(), tableCont);
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAAssignmentEditController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAAssignmentEditController.java
index 898f5c98443593843c651367ff8200c2780d4416..b92e1e4ba0766dd13bc18821ada292bf113b231c 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTAAssignmentEditController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAAssignmentEditController.java
@@ -41,7 +41,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -143,11 +142,11 @@ public class GTAAssignmentEditController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TDCols.title.i18nKey(), TDCols.title.ordinal()));
 		fileExistsRenderer = new WarningFlexiCellRenderer();
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TDCols.file.i18nKey(), TDCols.file.ordinal(), fileExistsRenderer));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.edit", TDCols.edit.ordinal(), "edit",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.edit", TDCols.edit.ordinal(), "edit",
 				new BooleanCellRenderer(
 						new StaticFlexiCellRenderer(translate("edit"), "edit"),
 						new StaticFlexiCellRenderer(translate("replace"), "edit"))));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.edit", translate("delete"), "delete"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.edit", translate("delete"), "delete"));
 		
 		taskModel = new TaskDefinitionTableModel(columnsModel);
 		taskDefTableEl = uifactory.addTableElement(getWindowControl(), "taskTable", taskModel, getTranslator(), tasksCont);
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAAvailableTaskController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAAvailableTaskController.java
index 4b881ff69e882b5c4df0ec44c68aedc13072b69c..d43cdf0f4f3cd870da2353bc059457ed8b3a0484 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTAAvailableTaskController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAAvailableTaskController.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
@@ -124,7 +123,7 @@ public class GTAAvailableTaskController extends FormBasicController {
 		if(preview) {
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ATDCols.preview.i18nKey(), ATDCols.preview.ordinal()));
 		}
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", -1, "select",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", -1, "select",
 				new StaticFlexiCellRenderer(translate("select"), "select", "btn btn-primary", "o_icon o_icon_submit")));
 		
 		taskModel = new AvailableTaskTableModel(columnsModel);
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java
index 44aa5be753f75a9c88c166504bcfb38b5de12755..4fec641c6dade62ba20e1bfa1385e3bbd51d5322 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupGradingController.java
@@ -37,7 +37,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColum
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.velocity.VelocityContainer;
@@ -164,7 +163,7 @@ public class GTACoachedGroupGradingController extends FormBasicController {
 				FlexiColumnModel col;
 				if(UserConstants.FIRSTNAME.equals(propName)
 						|| UserConstants.LASTNAME.equals(propName)) {
-					col = new StaticFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
+					col = new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
 							colIndex, userPropertyHandler.getName(), true, propName,
 							new StaticFlexiCellRenderer(userPropertyHandler.getName(), new TextFlexiCellRenderer()));
 				} else {
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java
index a0dc1b45666a168c291e1d4fc8f89b9e6544c327..0cb2d3be87ecdaa795f36e4a5ffa0598583062b0 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedGroupListController.java
@@ -34,7 +34,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFle
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.course.nodes.GTACourseNode;
@@ -87,7 +86,7 @@ public class GTACoachedGroupListController extends FormBasicController {
 		
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.taskStatus.i18nKey(), CGCols.taskStatus.ordinal(),
 				true, CGCols.taskStatus.name(), new TaskStatusCellRenderer(getTranslator())));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translate("select"), "select"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select"));
 		tableModel = new CoachGroupsTableModel(columnsModel);
 
 		tableEl = uifactory.addTableElement(getWindowControl(), "entries", tableModel, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java
index 0606b194d45c0c2ae0c851ea1c281d1fc0d56ea7..8ac1e0b1c7b9c203f6f6aef10a2de2c0cbae97f5 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
@@ -157,7 +156,7 @@ public class GTACoachedParticipantListController extends FormBasicController {
 				FlexiColumnModel col;
 				if(UserConstants.FIRSTNAME.equals(propName)
 						|| UserConstants.LASTNAME.equals(propName)) {
-					col = new StaticFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
+					col = new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
 							colIndex, userPropertyHandler.getName(), true, propName,
 							new StaticFlexiCellRenderer(userPropertyHandler.getName(), new TextFlexiCellRenderer()));
 				} else {
@@ -174,7 +173,7 @@ public class GTACoachedParticipantListController extends FormBasicController {
 		
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.taskStatus.i18nKey(), CGCols.taskStatus.ordinal(),
 				true, CGCols.taskStatus.name(), new TaskStatusCellRenderer(getTranslator())));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translate("select"), "select"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select"));
 		tableModel = new CoachParticipantsTableModel(userPropertyHandlers, getLocale(), columnsModel);
 
 		tableEl = uifactory.addTableElement(getWindowControl(), "entries", tableModel, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTASampleSolutionsEditController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTASampleSolutionsEditController.java
index e7a09109ccdacbb5696af6d0f322b832b731b0eb..6cf002930ce7c32d7f11761ad9c9987bfaeb66a9 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTASampleSolutionsEditController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTASampleSolutionsEditController.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -111,11 +110,11 @@ public class GTASampleSolutionsEditController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(SolCols.title.i18nKey(), SolCols.title.ordinal()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(SolCols.file.i18nKey(), SolCols.file.ordinal()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(SolCols.author.i18nKey(), SolCols.author.ordinal()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.edit", SolCols.edit.ordinal(), "edit",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.edit", SolCols.edit.ordinal(), "edit",
 				new BooleanCellRenderer(
 						new StaticFlexiCellRenderer(translate("edit"), "edit"),
 						new StaticFlexiCellRenderer(translate("replace"), "edit"))));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.edit", translate("delete"), "delete"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.edit", translate("delete"), "delete"));
 
 		solutionModel = new SolutionTableModel(columnsModel);
 		solutionTable = uifactory.addTableElement(getWindowControl(), "table", solutionModel, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java b/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java
index 3e63b2346e5a7db2ec9399a9627bf6a6417f4c37..8c07ff08e076669a6f2af6134786c944179648ec 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GroupAssessmentController.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColum
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
@@ -183,7 +182,7 @@ public class GroupAssessmentController extends FormBasicController {
 				FlexiColumnModel col;
 				if(UserConstants.FIRSTNAME.equals(propName)
 						|| UserConstants.LASTNAME.equals(propName)) {
-					col = new StaticFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
+					col = new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
 							colIndex, userPropertyHandler.getName(), true, propName,
 							new StaticFlexiCellRenderer(userPropertyHandler.getName(), new TextFlexiCellRenderer()));
 				} else {
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java b/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java
index ea6ae71da20db6903c056cc4153f2795d7ccb097..995f70c145d36df61d1d9cd98fca85ae1c8c5457 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java
@@ -47,7 +47,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -136,11 +135,11 @@ class SubmitDocumentsController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(docI18nKey, DocCols.document.ordinal()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DocCols.date.i18nKey(), DocCols.date.ordinal()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(DocCols.uploadedBy.i18nKey(), DocCols.uploadedBy.ordinal()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("edit", DocCols.edit.ordinal(), "edit",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", DocCols.edit.ordinal(), "edit",
 				new BooleanCellRenderer(
 						new StaticFlexiCellRenderer(translate("edit"), "edit"),
 						new StaticFlexiCellRenderer(translate("replace"), "edit"))));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", translate("delete"), "delete"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete"));
 		
 		model = new DocumentTableModel(columnsModel);
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", model, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/course/nodes/iq/IQRunController.java b/src/main/java/org/olat/course/nodes/iq/IQRunController.java
index f716c37f0447566e798d16277bc0a995b48cebf0..f9231f5baa9b36d7b174b94077b97ad61b769cba 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQRunController.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQRunController.java
@@ -67,7 +67,7 @@ import org.olat.course.DisposedCourseRestartController;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
 import org.olat.course.assessment.AssessmentManager;
-import org.olat.course.assessment.AssessmentNotificationsHandler;
+import org.olat.course.assessment.manager.AssessmentNotificationsHandler;
 import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.nodes.CourseNode;
@@ -92,6 +92,7 @@ import org.olat.modules.iq.IQSubmittedEvent;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.util.logging.activity.LoggingResourceable;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Description:<BR>
@@ -128,7 +129,10 @@ public class IQRunController extends BasicController implements GenericEventList
 	
 	private OLATResourceable assessmentInstanceOres;
 	
-	private final IQManager iqManager;
+	@Autowired
+	private IQManager iqManager;
+	@Autowired
+	private AssessmentNotificationsHandler assessmentNotificationsHandler;
 	
 	/**
 	 * Constructor for a test run controller
@@ -152,7 +156,6 @@ public class IQRunController extends BasicController implements GenericEventList
 		this.assessmentInstanceOres = OresHelper.createOLATResourceableType(AssessmentInstance.class);
 		
 		this.userSession = ureq.getUserSession();
-		iqManager = CoreSpringFactory.getImpl(IQManager.class);
 		
 		addLoggingResourceable(LoggingResourceable.wrap(courseNode));
 		
@@ -469,9 +472,8 @@ public class IQRunController extends BasicController implements GenericEventList
 			acn.updateUserScoreEvaluation(sceval, userCourseEnv, getIdentity(), incrementUserAttempts);
 				
 			// Mark publisher for notifications
-			AssessmentNotificationsHandler anh = AssessmentNotificationsHandler.getInstance();
 			Long courseId = userCourseEnv.getCourseEnvironment().getCourseResourceableId();
-			anh.markPublisherNews(getIdentity(), courseId);
+			assessmentNotificationsHandler.markPublisherNews(getIdentity(), courseId);
 			if(!assessmentStopped) {
 			  assessmentStopped = true;					  
 			  AssessmentEvent assessmentStoppedEvent = new AssessmentEvent(AssessmentEvent.TYPE.STOPPED, userSession);
diff --git a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentDetailsController.java b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentDetailsController.java
index 1711070cd9f1d277406c0e3937a76857f7ed6ec3..6642523c2b91db3105071165f8ef06ce8cbdcceb 100644
--- a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentDetailsController.java
+++ b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentDetailsController.java
@@ -33,7 +33,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
@@ -85,7 +84,7 @@ public class QTI21AssessmentDetailsController extends FormBasicController {
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.lastModified.i18nKey(), TSCols.lastModified.ordinal()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(TSCols.results.i18nKey(), TSCols.results.ordinal(), "result",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(TSCols.results.i18nKey(), TSCols.results.ordinal(), "result",
 				new BooleanCellRenderer(new StaticFlexiCellRenderer(translate(TSCols.results.i18nKey()), "result"), null)));
 
 		tableModel = new QTI21TestSessionTableModel(columnsModel);
diff --git a/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java b/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java
index c82fdc1e2a8d5a038770338253eefa414b0eaa90..cd73d218a1bc02a3822dbd11a6fb2b0ff5791dc2 100644
--- a/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java
+++ b/src/main/java/org/olat/course/nodes/ta/ConvertToGTACourseNode.java
@@ -63,6 +63,7 @@ import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.modules.ModuleConfiguration;
+import org.olat.modules.assessment.AssessmentEntry;
 import org.olat.properties.Property;
 
 /**
@@ -217,55 +218,24 @@ public class ConvertToGTACourseNode {
 		CourseEnvironment courseEnv = course.getCourseEnvironment();
 		CoursePropertyManager propertyMgr = courseEnv.getCoursePropertyManager();
 		
-		Map<Long,AssessmentDatas> datas = new HashMap<>();
-		List<Property> properties = propertyMgr.listCourseNodeProperties(sourceNode, null, null, null);
-		for(Property property:properties) {
-			String name = property.getName();
-			if(AssessmentManager.SCORE.equals(name) || AssessmentManager.PASSED.equals(name)
-					|| AssessmentManager.ATTEMPTS.equals(name) || AssessmentManager.COMMENT.equals(name)
-					|| AssessmentManager.COACH_COMMENT.equals(name)) {
-				
-				Identity identity = property.getIdentity();
-				AssessmentDatas assessmentDatas;
-				if(datas.containsKey(identity.getKey())) {
-					assessmentDatas = datas.get(identity.getKey());
-				} else {
-					assessmentDatas = new AssessmentDatas(identity);
-					datas.put(identity.getKey(), assessmentDatas);
-				}
-				
-				switch(name) {
-					case AssessmentManager.SCORE:
-						assessmentDatas.setScore(property.getFloatValue());
-						break;
-					case AssessmentManager.PASSED:
-						String pass = property.getStringValue();
-						if(StringHelper.containsNonWhitespace(pass)) {
-							assessmentDatas.setPassed("true".equals(pass));
-						}
-						break;
-					case AssessmentManager.ATTEMPTS:
-						assessmentDatas.setAttempts(property.getLongValue());
-						break;
-					case AssessmentManager.COMMENT:
-						assessmentDatas.setComment(property.getTextValue());
-						break;
-					case AssessmentManager.COACH_COMMENT:
-						assessmentDatas.setCoachComment(property.getTextValue());
-						break;
-				}
-			}
+		Map<Long,AssessmentEntry> datas = new HashMap<>();
+		List<AssessmentEntry> properties = courseEnv.getAssessmentManager().getAssessmentData(sourceNode);
+
+		for(AssessmentEntry property:properties) {
+			Identity identity = property.getIdentity();
+			datas.put(identity.getKey(), property);
 		}
 		properties = null;
 		DBFactory.getInstance().getCurrentEntityManager().clear();
 		
 		AssessmentManager assessmentMgr = courseEnv.getAssessmentManager();
-		for(AssessmentDatas assessmentDatas:datas.values()) {
-			Identity assessedIdentity = securityManager.loadIdentityByKey(assessmentDatas.getIdentity().getKey());
+		for(AssessmentEntry assessmentData:datas.values()) {
+			Identity assessedIdentity = securityManager.loadIdentityByKey(assessmentData.getIdentity().getKey());
 			
-			if(assessmentDatas.getPassed() != null || assessmentDatas.getScore() != null) {
+			if(assessmentData.getPassed() != null || assessmentData.getScore() != null) {
 				UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
-				ScoreEvaluation scoreEval = new ScoreEvaluation(assessmentDatas.getScore(), assessmentDatas.getPassed());
+				Float score = assessmentData.getScore() == null ? null : assessmentData.getScore().floatValue();
+				ScoreEvaluation scoreEval = new ScoreEvaluation(score, assessmentData.getPassed());
 				assessmentMgr.saveScoreEvaluation(gtaNode, null, assessedIdentity, scoreEval, userCourseEnv, false);
 				
 				//set graded
@@ -277,16 +247,16 @@ public class ConvertToGTACourseNode {
 				}
 			}
 			
-			if(assessmentDatas.getAttempts() != null) {
-				assessmentMgr.saveNodeAttempts(gtaNode, null, assessedIdentity, assessmentDatas.getAttempts().intValue());
+			if(assessmentData.getAttempts() != null) {
+				assessmentMgr.saveNodeAttempts(gtaNode, null, assessedIdentity, assessmentData.getAttempts().intValue());
 			}
 			
-			if(StringHelper.containsNonWhitespace(assessmentDatas.getCoachComment())) {
-				assessmentMgr.saveNodeCoachComment(gtaNode, assessedIdentity, assessmentDatas.getCoachComment());
+			if(StringHelper.containsNonWhitespace(assessmentData.getCoachComment())) {
+				assessmentMgr.saveNodeCoachComment(gtaNode, assessedIdentity, assessmentData.getCoachComment());
 			}
 			
-			if(StringHelper.containsNonWhitespace(assessmentDatas.getComment())) {
-				assessmentMgr.saveNodeComment(gtaNode, null, assessedIdentity, assessmentDatas.getComment());
+			if(StringHelper.containsNonWhitespace(assessmentData.getComment())) {
+				assessmentMgr.saveNodeComment(gtaNode, null, assessedIdentity, assessmentData.getComment());
 			}
 		}
 		
@@ -426,62 +396,4 @@ public class ConvertToGTACourseNode {
 			}	
 		}
 	}
-
-	private static class AssessmentDatas {
-		
-		private final Identity identity;
-		private Boolean passed;
-		private Float score;
-		private String comment;
-		private String coachComment;
-		private Long attempts;
-		
-		public AssessmentDatas(Identity identity) {
-			this.identity = identity;
-		}
-
-		public Boolean getPassed() {
-			return passed;
-		}
-
-		public void setPassed(Boolean passed) {
-			this.passed = passed;
-		}
-
-		public Float getScore() {
-			return score;
-		}
-
-		public void setScore(Float score) {
-			this.score = score;
-		}
-
-		public String getComment() {
-			return comment;
-		}
-
-		public void setComment(String comment) {
-			this.comment = comment;
-		}
-
-		public String getCoachComment() {
-			return coachComment;
-		}
-
-		public void setCoachComment(String coachComment) {
-			this.coachComment = coachComment;
-		}
-
-		public Long getAttempts() {
-			return attempts;
-		}
-
-		public void setAttempts(Long attempts) {
-			this.attempts = attempts;
-		}
-
-		public Identity getIdentity() {
-			return identity;
-		}
-	}
 }
diff --git a/src/main/java/org/olat/course/properties/PersistingCoursePropertyManager.java b/src/main/java/org/olat/course/properties/PersistingCoursePropertyManager.java
index 82f3b8aaf801cfccf7a10109a09d0f39107fccfd..8ff2a49428423295c807e188dfe6792152806900 100644
--- a/src/main/java/org/olat/course/properties/PersistingCoursePropertyManager.java
+++ b/src/main/java/org/olat/course/properties/PersistingCoursePropertyManager.java
@@ -25,24 +25,22 @@
 
 package org.olat.course.properties;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
 
-import javax.persistence.TypedQuery;
-
-import org.olat.basesecurity.IdentityImpl;
-import org.olat.core.commons.persistence.DBFactory;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
 import org.olat.core.manager.BasicManager;
-import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
 import org.olat.course.nodes.CourseNode;
 import org.olat.group.BusinessGroup;
+import org.olat.modules.assessment.manager.AssessmentEntryDAO;
 import org.olat.properties.NarrowedPropertyManager;
 import org.olat.properties.Property;
 import org.olat.resource.OLATResource;
@@ -225,34 +223,8 @@ public class PersistingCoursePropertyManager extends BasicManager implements Cou
 	 */
 	@Override
 	public List<Identity> getAllIdentitiesWithCourseAssessmentData(Collection<Identity> excludeIdentities) {
-		StringBuilder query = new StringBuilder();
-		query.append("select distinct i from ")
-			.append(IdentityImpl.class.getName()).append(" as i,")
-			.append(Property.class.getName()).append(" as p")
-			.append(" where i = p.identity and p.resourceTypeName = :resname")
-			.append(" and p.resourceTypeId = :resid")
-			.append(" and p.identity is not null")
-			.append(" and p.name in ('").append(AssessmentManager.SCORE).append("','").append(AssessmentManager.PASSED).append("')");
-		
-		if(excludeIdentities != null && !excludeIdentities.isEmpty()) {
-			query.append(" and p.identity.key not in (:excludeIdentities) ");
-		}
-
-		TypedQuery<Identity> db = DBFactory.getInstance().getCurrentEntityManager()
-				.createQuery(query.toString(), Identity.class)
-				.setParameter("resid", ores.getResourceableId())
-				.setParameter("resname", ores.getResourceableTypeName());
-		if(excludeIdentities != null && !excludeIdentities.isEmpty()) {
-			List<Long> excludeKeys = new ArrayList<Long>();
-			for(Identity identity:excludeIdentities) {
-				excludeKeys.add(identity.getKey());
-			}
-			//limit because Oracle and Hibernate doesn't like more than 1000
-			if(excludeKeys.size() > 900) {
-				excludeKeys = excludeKeys.subList(0, 900);
-			}
-			db.setParameter("excludeIdentities", excludeKeys);
-		}
-		return db.getResultList();
+		ICourse course = CourseFactory.loadCourse(ores);
+		AssessmentEntryDAO courseNodeAssessmentDao = CoreSpringFactory.getImpl(AssessmentEntryDAO.class);
+		return courseNodeAssessmentDao.getAllIdentitiesWithAssessmentData(course.getCourseEnvironment().getCourseGroupManager().getCourseEntry());
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/reminder/manager/ReminderRuleDAO.java b/src/main/java/org/olat/course/reminder/manager/ReminderRuleDAO.java
index 00ec90da967bd3223b1c57817284f1c4fcc38519..7bf5024389d5277a1630ae35d1e83ed1c6149883 100644
--- a/src/main/java/org/olat/course/reminder/manager/ReminderRuleDAO.java
+++ b/src/main/java/org/olat/course/reminder/manager/ReminderRuleDAO.java
@@ -33,6 +33,7 @@ import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.id.Identity;
 import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.nodes.CourseNode;
+import org.olat.repository.RepositoryEntryRef;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -48,33 +49,28 @@ public class ReminderRuleDAO {
 	@Autowired
 	private DB dbInstance;
 
-	public Map<Long,Float> getScores(Long courseResourceId, CourseNode node, List<Identity> identities) {
+
+	public Map<Long,Float> getScores(RepositoryEntryRef entry, CourseNode node, List<Identity> identities) {
 		if(identities == null || identities.isEmpty()) {
 			return new HashMap<Long,Float>();
 		}
 
-		List<Long> identityKeys = PersistenceHelper.toKeys(identities);
-
-		StringBuilder sb = new StringBuilder();
-		sb.append("select p.identity.key, p.floatValue from org.olat.properties.Property as p")
-		  .append(" where p.resourceTypeId = :resId and p.resourceTypeName='CourseModule'")
-		  .append(" and p.name='").append(AssessmentManager.SCORE).append("'")
-		  .append(" and p.category=:category");
-
 		Set<Long> identityKeySet = null;
-		if(identityKeys.size() < 100) {
-			sb.append(" and p.identity.key in (:identityKeys)");
-		} else {
-			identityKeySet = new HashSet<Long>(identityKeys);
+		StringBuilder sb = new StringBuilder();
+		sb.append("select nodeassessment.identity.key, nodeassessment.score from coursenodeassessment nodeassessment")
+		  .append(" where nodeassessment.courseEntry.key=:courseEntryKey and nodeassessment.courseNodeIdent=:courseNodeIdent");
+		if(identities.size() < 50) {
+			sb.append(" and nodeassessment.identity.key in (:identityKeys)");
 		}
-		String myCategory = buildCourseNodePropertyCategory(node);
 
 		TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Object[].class)
-				.setParameter("resId", courseResourceId)
-				.setParameter("category", myCategory);
-		if(identityKeys.size() < 100) {
-			query.setParameter("identityKeys", identityKeys);
+				.setParameter("courseEntryKey", entry.getKey())
+				.setParameter("courseNodeIdent", node.getIdent());
+		if(identities.size() < 50) {
+			query.setParameter("identityKeys", PersistenceHelper.toKeys(identities));
+		} else {
+			identityKeySet = new HashSet<>(PersistenceHelper.toKeys(identities));
 		}
 
 		List<Object[]> infoList = query.getResultList();
@@ -82,40 +78,34 @@ public class ReminderRuleDAO {
 		for(Object[] infos:infoList) {
 			Long identityKey = (Long)infos[0];
 			if(identityKeySet == null || identityKeySet.contains(identityKey)) {
-				Float score = (Float)infos[1];
-				dateMap.put(identityKey, score);
+				Number score = (Number)infos[1];
+				dateMap.put(identityKey, score.floatValue());
 			}
 		}
 		return dateMap;
 	}
 	
-	public Map<Long,Integer> getAttempts(Long courseResourceId, CourseNode node, List<Identity> identities) {
+	public Map<Long,Integer> getAttempts(RepositoryEntryRef entry, CourseNode node, List<Identity> identities) {
 		if(identities == null || identities.isEmpty()) {
 			return new HashMap<Long,Integer>();
 		}
 
-		List<Long> identityKeys = PersistenceHelper.toKeys(identities);
-
-		StringBuilder sb = new StringBuilder();
-		sb.append("select p.identity.key, p.longValue from org.olat.properties.Property as p")
-		  .append(" where p.resourceTypeId = :resId and p.resourceTypeName='CourseModule'")
-		  .append(" and p.name='").append(AssessmentManager.ATTEMPTS).append("'")
-		  .append(" and p.category=:category");
-
 		Set<Long> identityKeySet = null;
-		if(identityKeys.size() < 100) {
-			sb.append(" and p.identity.key in (:identityKeys)");
-		} else {
-			identityKeySet = new HashSet<Long>(identityKeys);
+		StringBuilder sb = new StringBuilder();
+		sb.append("select nodeassessment.identity.key, nodeassessment.attempts from coursenodeassessment nodeassessment")
+		  .append(" where nodeassessment.courseEntry.key=:courseEntryKey and nodeassessment.courseNodeIdent=:courseNodeIdent");
+		if(identities.size() < 50) {
+			sb.append(" and nodeassessment.identity.key in (:identityKeys)");
 		}
-		String myCategory = buildCourseNodePropertyCategory(node);
 
 		TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Object[].class)
-				.setParameter("resId", courseResourceId)
-				.setParameter("category", myCategory);
-		if(identityKeys.size() < 100) {
-			query.setParameter("identityKeys", identityKeys);
+				.setParameter("courseEntryKey", entry.getKey())
+				.setParameter("courseNodeIdent", node.getIdent());
+		if(identities.size() < 50) {
+			query.setParameter("identityKeys", PersistenceHelper.toKeys(identities));
+		} else {
+			identityKeySet = new HashSet<>(PersistenceHelper.toKeys(identities));
 		}
 
 		List<Object[]> infoList = query.getResultList();
@@ -130,33 +120,27 @@ public class ReminderRuleDAO {
 		return dateMap;
 	}
 	
-	public Map<Long,Date> getInitialAttemptDates(Long courseResourceId, CourseNode node, List<Identity> identities) {
+	public Map<Long,Date> getInitialAttemptDates(RepositoryEntryRef entry, CourseNode node, List<Identity> identities) {
 		if(identities == null || identities.isEmpty()) {
 			return new HashMap<Long,Date>();
 		}
 
-		List<Long> identityKeys = PersistenceHelper.toKeys(identities);
-
-		StringBuilder sb = new StringBuilder();
-		sb.append("select p.identity.key, p.creationDate from org.olat.properties.Property as p")
-		  .append(" where p.resourceTypeId = :resId and p.resourceTypeName='CourseModule'")
-		  .append(" and p.name='").append(AssessmentManager.ATTEMPTS).append("'")
-		  .append(" and p.category=:category");
-
 		Set<Long> identityKeySet = null;
-		if(identityKeys.size() < 100) {
-			sb.append(" and p.identity.key in (:identityKeys)");
-		} else {
-			identityKeySet = new HashSet<Long>(identityKeys);
+		StringBuilder sb = new StringBuilder();
+		sb.append("select nodeassessment.identity.key, nodeassessment.creationDate from coursenodeassessment nodeassessment")
+		  .append(" where nodeassessment.courseEntry.key=:courseEntryKey and nodeassessment.courseNodeIdent=:courseNodeIdent");
+		if(identities.size() < 50) {
+			sb.append(" and nodeassessment.identity.key in (:identityKeys)");
 		}
-		String myCategory = buildCourseNodePropertyCategory(node);
 
 		TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Object[].class)
-				.setParameter("resId", courseResourceId)
-				.setParameter("category", myCategory);
-		if(identityKeys.size() < 100) {
-			query.setParameter("identityKeys", identityKeys);
+				.setParameter("courseEntryKey", entry.getKey())
+				.setParameter("courseNodeIdent", node.getIdent());
+		if(identities.size() < 50) {
+			query.setParameter("identityKeys", PersistenceHelper.toKeys(identities));
+		} else {
+			identityKeySet = new HashSet<>(PersistenceHelper.toKeys(identities));
 		}
 
 		List<Object[]> infoList = query.getResultList();
@@ -171,33 +155,27 @@ public class ReminderRuleDAO {
 		return dateMap;
 	}
 	
-	public Map<Long,Boolean> getPassed(Long courseResourceId, CourseNode node, List<Identity> identities) {
+	public Map<Long,Boolean> getPassed(RepositoryEntryRef entry, CourseNode node, List<Identity> identities) {
 		if(identities == null || identities.isEmpty()) {
 			return new HashMap<Long,Boolean>();
 		}
 
-		List<Long> identityKeys = PersistenceHelper.toKeys(identities);
-
-		StringBuilder sb = new StringBuilder();
-		sb.append("select p.identity.key, p.stringValue from org.olat.properties.Property as p")
-		  .append(" where p.resourceTypeId = :resId and p.resourceTypeName='CourseModule'")
-		  .append(" and p.name='").append(AssessmentManager.PASSED).append("'")
-		  .append(" and p.category=:category");
-
 		Set<Long> identityKeySet = null;
-		if(identityKeys.size() < 100) {
-			sb.append(" and p.identity.key in (:identityKeys)");
-		} else {
-			identityKeySet = new HashSet<Long>(identityKeys);
+		StringBuilder sb = new StringBuilder();
+		sb.append("select nodeassessment.identity.key, nodeassessment.passed from coursenodeassessment nodeassessment")
+		  .append(" where nodeassessment.courseEntry.key=:courseEntryKey and nodeassessment.courseNodeIdent=:courseNodeIdent");
+		if(identities.size() < 50) {
+			sb.append(" and nodeassessment.identity.key in (:identityKeys)");
 		}
-		String myCategory = buildCourseNodePropertyCategory(node);
 
 		TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Object[].class)
-				.setParameter("resId", courseResourceId)
-				.setParameter("category", myCategory);
-		if(identityKeys.size() < 100) {
-			query.setParameter("identityKeys", identityKeys);
+				.setParameter("courseEntryKey", entry.getKey())
+				.setParameter("courseNodeIdent", node.getIdent());
+		if(identities.size() < 50) {
+			query.setParameter("identityKeys", PersistenceHelper.toKeys(identities));
+		} else {
+			identityKeySet = new HashSet<>(PersistenceHelper.toKeys(identities));
 		}
 
 		List<Object[]> infoList = query.getResultList();
@@ -211,10 +189,4 @@ public class ReminderRuleDAO {
 		}
 		return dateMap;
 	}
-	
-	private String buildCourseNodePropertyCategory(CourseNode node) {
-		String type = (node.getType().length() > 4 ? node.getType().substring(0, 4) : node.getType());
-		return ("NID:" + type + "::" + node.getIdent());
-	}
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/reminder/rule/AttemptsRuleSPI.java b/src/main/java/org/olat/course/reminder/rule/AttemptsRuleSPI.java
index d204cc5d8fd1a1ccb7ebca266621307cc651703a..a630bcca0fbc5a56fd74948787117fd4d3344168 100644
--- a/src/main/java/org/olat/course/reminder/rule/AttemptsRuleSPI.java
+++ b/src/main/java/org/olat/course/reminder/rule/AttemptsRuleSPI.java
@@ -82,7 +82,7 @@ public class AttemptsRuleSPI implements FilterRuleSPI {
 			ICourse course = CourseFactory.loadCourse(entry.getOlatResource());
 			CourseNode courseNode = course.getRunStructure().getNode(nodeIdent);
 
-			Map<Long, Integer> attempts = helperDao.getAttempts(entry.getOlatResource().getResourceableId(), courseNode, identities);
+			Map<Long, Integer> attempts = helperDao.getAttempts(entry, courseNode, identities);
 			
 			for(Iterator<Identity> identityIt=identities.iterator(); identityIt.hasNext(); ) {
 				Identity identity = identityIt.next();
diff --git a/src/main/java/org/olat/course/reminder/rule/InitialAttemptsRuleSPI.java b/src/main/java/org/olat/course/reminder/rule/InitialAttemptsRuleSPI.java
index eb8c5e1640c093454899af23267a1fa761d60b9d..2fee1ec95040a5738ac5525ec8a08989dea42dab 100644
--- a/src/main/java/org/olat/course/reminder/rule/InitialAttemptsRuleSPI.java
+++ b/src/main/java/org/olat/course/reminder/rule/InitialAttemptsRuleSPI.java
@@ -80,7 +80,7 @@ public class InitialAttemptsRuleSPI extends AbstractLaunchDateRuleSPI {
 			ICourse course = CourseFactory.loadCourse(courseResourceId);
 			CourseNode courseNode = course.getRunStructure().getNode(nodeIdent);
 
-			return helperDao.getInitialAttemptDates(courseResourceId, courseNode, identities);
+			return helperDao.getInitialAttemptDates(entry, courseNode, identities);
 		} else {
 			return null;
 		}
diff --git a/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java b/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java
index d365bbe40e0a5a475e85b5d2e59fb47abbb059f6..20363103622faf520423e21ac146cb2190b8f197 100644
--- a/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java
+++ b/src/main/java/org/olat/course/reminder/rule/PassedRuleSPI.java
@@ -80,7 +80,7 @@ public class PassedRuleSPI implements FilterRuleSPI {
 			ICourse course = CourseFactory.loadCourse(entry.getOlatResource());
 			CourseNode courseNode = course.getRunStructure().getNode(nodeIdent);
 			
-			Map<Long, Boolean> passeds = helperDao.getPassed(entry.getOlatResource().getResourceableId(), courseNode, identities);
+			Map<Long, Boolean> passeds = helperDao.getPassed(entry, courseNode, identities);
 			
 			if("passed".equals(status)) {
 				for(Iterator<Identity> identityIt=identities.iterator(); identityIt.hasNext(); ) {
diff --git a/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java b/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java
index bf1290ccefd13c1e0e022c84ef900d4a9ce21249..4280160e7888004193e078993d8c14b98bdf1093 100644
--- a/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java
+++ b/src/main/java/org/olat/course/reminder/rule/ScoreRuleSPI.java
@@ -83,7 +83,7 @@ public class ScoreRuleSPI implements FilterRuleSPI {
 			ICourse course = CourseFactory.loadCourse(entry.getOlatResource());
 			CourseNode courseNode = course.getRunStructure().getNode(nodeIdent);
 			
-			Map<Long, Float> scores = helperDao.getScores(entry.getOlatResource().getResourceableId(), courseNode, identities);
+			Map<Long, Float> scores = helperDao.getScores(entry, courseNode, identities);
 			
 			for(Iterator<Identity> identityIt=identities.iterator(); identityIt.hasNext(); ) {
 				Identity identity = identityIt.next();
diff --git a/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java b/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java
index c122e8bf8e41b62cdfaea488873c54f7324c2e45..fb217c13a7a8b716236f4d85651faa8061239173 100644
--- a/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java
+++ b/src/main/java/org/olat/course/reminder/ui/CourseReminderListController.java
@@ -36,7 +36,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
@@ -110,7 +109,7 @@ public class CourseReminderListController extends FormBasicController implements
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, ReminderCols.id.i18nKey(), ReminderCols.id.ordinal(),
 				true, ReminderCols.id.name()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(ReminderCols.description.i18nKey(), ReminderCols.description.ordinal(),
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ReminderCols.description.i18nKey(), ReminderCols.description.ordinal(),
 				"edit", true, ReminderCols.description.name(), new StaticFlexiCellRenderer("edit", new TextFlexiCellRenderer())));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ReminderCols.creator.i18nKey(), ReminderCols.creator.ordinal(),
 				true, ReminderCols.creator.name()));
diff --git a/src/main/java/org/olat/course/reminder/ui/CourseReminderLogsController.java b/src/main/java/org/olat/course/reminder/ui/CourseReminderLogsController.java
index 0f8c9b539ae3d215ecc02fd5d1f3221c265392fb..e6ca4dadd2efd023cd4fea36efe1938738303014 100644
--- a/src/main/java/org/olat/course/reminder/ui/CourseReminderLogsController.java
+++ b/src/main/java/org/olat/course/reminder/ui/CourseReminderLogsController.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.Controller;
@@ -107,7 +106,7 @@ public class CourseReminderLogsController extends FormBasicController {
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(SendCols.status.i18nKey(), SendCols.status.ordinal(),
 				 true, SendCols.status.name(), new StatusCellRenderer()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(SendCols.reminder.i18nKey(), SendCols.reminder.ordinal(),
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(SendCols.reminder.i18nKey(), SendCols.reminder.ordinal(),
 				"reminder", true, SendCols.reminder.name(), new StaticFlexiCellRenderer("reminder", new TextFlexiCellRenderer())));
 
 		if(isAdministrativeUser) {
@@ -126,7 +125,7 @@ public class CourseReminderLogsController extends FormBasicController {
 			FlexiColumnModel col;
 			if(UserConstants.FIRSTNAME.equals(propName)
 					|| UserConstants.LASTNAME.equals(propName)) {
-				col = new StaticFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
+				col = new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
 						colIndex, userPropertyHandler.getName(), true, propName,
 						new StaticFlexiCellRenderer(userPropertyHandler.getName(), new TextFlexiCellRenderer()));
 			} else {
@@ -138,7 +137,7 @@ public class CourseReminderLogsController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(SendCols.sendTime.i18nKey(), SendCols.sendTime.ordinal(),
 				true, SendCols.sendTime.name()));
 		//user properties
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("resend", translate("resend"), "resend"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("resend", translate("resend"), "resend"));
 		
 		tableModel = new CourseSendReminderTableModel(columnsModel);
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 20, false, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/course/reminder/ui/CourseSendReminderListController.java b/src/main/java/org/olat/course/reminder/ui/CourseSendReminderListController.java
index b54d9c1d343e3db9f19dff12d43fbf6af659c228..7e43e1381e39134021abac3e9573031d55055d5b 100644
--- a/src/main/java/org/olat/course/reminder/ui/CourseSendReminderListController.java
+++ b/src/main/java/org/olat/course/reminder/ui/CourseSendReminderListController.java
@@ -38,7 +38,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
@@ -117,7 +116,7 @@ public class CourseSendReminderListController extends FormBasicController {
 			FlexiColumnModel col;
 			if(UserConstants.FIRSTNAME.equals(propName)
 					|| UserConstants.LASTNAME.equals(propName)) {
-				col = new StaticFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
+				col = new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
 						colIndex, userPropertyHandler.getName(), true, propName,
 						new StaticFlexiCellRenderer(userPropertyHandler.getName(), new TextFlexiCellRenderer()));
 			} else {
@@ -126,7 +125,7 @@ public class CourseSendReminderListController extends FormBasicController {
 			columnsModel.addFlexiColumnModel(col);
 		}
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(SendCols.sendTime.i18nKey(), SendCols.sendTime.ordinal(), true, SendCols.sendTime.name()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("resend", translate("resend"), "resend"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("resend", translate("resend"), "resend"));
 		
 		tableModel = new CourseSendReminderTableModel(columnsModel);
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 20, false, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java
index c58980fe134e744695a8111f2a5824d419187f7e..1454540efd1fac3ce605d9831194d02fdd24bf5a 100644
--- a/src/main/java/org/olat/course/run/CourseRuntimeController.java
+++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java
@@ -90,7 +90,8 @@ import org.olat.course.assessment.AssessmentMainController;
 import org.olat.course.assessment.AssessmentModule;
 import org.olat.course.assessment.CoachingGroupAccessAssessmentCallback;
 import org.olat.course.assessment.FullAccessAssessmentCallback;
-import org.olat.course.assessment.ui.AssessmentModeListController;
+import org.olat.course.assessment.ui.mode.AssessmentModeListController;
+import org.olat.course.assessment.ui.tool.AssessmentOverviewController;
 import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementController;
 import org.olat.course.certificate.ui.CertificatesOptionsController;
 import org.olat.course.config.CourseConfig;
@@ -148,7 +149,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	private Delayed delayedClose;
 	//tools
 	private Link folderLink,
-		assessmentLink, archiverLink,
+		assessmentLink, assessment_v2_Link, archiverLink,
 		courseStatisticLink, surveyStatisticLink, testStatisticLink,
 		areaLink, dbLink,
 		//settings
@@ -169,6 +170,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	private CourseOptionsController optionsToolCtr;
 	private CourseRemindersController remindersCtrl;
 	private AssessmentMainController assessmentToolCtr;
+	private AssessmentOverviewController assessmentTool_v2_Ctr;
 	private MembersManagementMainController membersCtrl;
 	private StatisticCourseNodesController statsToolCtr;
 	private AssessmentModeListController assessmentModeCtrl;
@@ -391,6 +393,11 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 				assessmentLink = LinkFactory.createToolLink("assessment",translate("command.openassessment"), this, "o_icon_assessment_tool");
 				assessmentLink.setElementCssClass("o_sel_course_assessment_tool");
 				tools.addComponent(assessmentLink);
+				
+				assessment_v2_Link = LinkFactory.createToolLink("assessment", translate("command.openassessment") + " v2", this, "o_icon_rocket");
+				assessment_v2_Link.setElementCssClass("o_sel_course_assessment_tool");
+				tools.addComponent(assessment_v2_Link);
+				
 			}
 			if (reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_ARCHIVING)) {
 				archiverLink = LinkFactory.createToolLink("archiver", translate("command.openarchiver"), this, "o_icon_archive_tool");
@@ -718,6 +725,8 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			doAssessmentSurveyStatistics(ureq);
 		} else if(assessmentLink == source) {
 			doAssessmentTool(ureq);
+		} else if(assessment_v2_Link == source) {
+			doAssessmentTool_v2(ureq);
 		} else if(calendarLink == source) {
 			launchCalendar(ureq);
 		} else if(chatLink == source) {
@@ -1277,6 +1286,42 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 		return null;
 	}
 	
+	private Activateable2 doAssessmentTool_v2(UserRequest ureq) {
+		if(delayedClose == Delayed.assessmentTool || requestForClose(ureq)) {
+			OLATResourceable ores = OresHelper.createOLATResourceableType("assessmentTool");
+			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
+			WindowControl swControl = addToHistory(ureq, ores, null);
+			
+			// 1) course admins and users with tool right: full access
+			if (reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) {
+				removeCustomCSS(ureq);
+				AssessmentOverviewController ctrl = new AssessmentOverviewController(ureq, swControl, toolbarPanel,
+						getRepositoryEntry(), new FullAccessAssessmentCallback(reSecurity.isEntryAdmin()));
+				ctrl.activate(ureq, null, null);
+				listenTo(ctrl);
+				assessmentTool_v2_Ctr = pushController(ureq, translate("command.openassessment"), ctrl);
+				currentToolCtr = assessmentTool_v2_Ctr;
+				setActiveTool(assessmentLink);
+				return assessmentToolCtr;
+			}
+			// 2) users with coach right: limited access to coached groups
+			if (reSecurity.isCourseCoach() || reSecurity.isGroupCoach()) {
+				removeCustomCSS(ureq);
+				AssessmentOverviewController ctrl = new AssessmentOverviewController(ureq, swControl, toolbarPanel,
+						getRepositoryEntry(), new CoachingGroupAccessAssessmentCallback());
+				ctrl.activate(ureq, null, null);
+				listenTo(ctrl);
+				assessmentTool_v2_Ctr = pushController(ureq, translate("command.openassessment"), ctrl);
+				currentToolCtr = assessmentTool_v2_Ctr;
+				setActiveTool(assessmentLink);
+				return assessmentToolCtr;
+			}
+		} else {
+			delayedClose = Delayed.assessmentTool;
+		}
+		return null;
+	}
+	
 	private void doEfficiencyStatements(UserRequest ureq) {
 		if(delayedClose == Delayed.efficiencyStatements || requestForClose(ureq)) {
 			// will not be disposed on course run dispose, popus up as new browserwindow
diff --git a/src/main/java/org/olat/course/run/environment/CourseEnvironmentImpl.java b/src/main/java/org/olat/course/run/environment/CourseEnvironmentImpl.java
index a7dad723660cadc2e2812fee04d40c44ecfc07f8..e76f292de1d075bb0a6b6e55ea8990c2033cb179 100644
--- a/src/main/java/org/olat/course/run/environment/CourseEnvironmentImpl.java
+++ b/src/main/java/org/olat/course/run/environment/CourseEnvironmentImpl.java
@@ -31,7 +31,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.course.PersistingCourseImpl;
 import org.olat.course.Structure;
 import org.olat.course.assessment.AssessmentManager;
-import org.olat.course.assessment.NewCachePersistingAssessmentManager;
+import org.olat.course.assessment.manager.CourseAssessmentManagerImpl;
 import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.auditing.UserNodeAuditManagerImpl;
 import org.olat.course.config.CourseConfig;
@@ -106,7 +106,7 @@ public class CourseEnvironmentImpl implements CourseEnvironment {
 		if(assessmentManager == null) {
 			synchronized(this) {
 				if(assessmentManager == null) {
-					assessmentManager = NewCachePersistingAssessmentManager.getInstance(course);
+					assessmentManager = new CourseAssessmentManagerImpl(cgm.getCourseEntry());
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/course/run/preview/PreviewAssessmentManager.java b/src/main/java/org/olat/course/run/preview/PreviewAssessmentManager.java
index c81d8d846db3b8c4c173e48b0ef6fa024001e1a6..242f9ece90590a615b496b446d01ab3313ac6ca5 100644
--- a/src/main/java/org/olat/course/run/preview/PreviewAssessmentManager.java
+++ b/src/main/java/org/olat/course/run/preview/PreviewAssessmentManager.java
@@ -25,6 +25,7 @@
 
 package org.olat.course.run.preview;
 
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -39,6 +40,7 @@ import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.modules.assessment.AssessmentEntry;
 
 /**
  * Initial Date:  08.02.2005
@@ -58,6 +60,11 @@ final class PreviewAssessmentManager extends BasicManager implements AssessmentM
 		nodeScores.put(courseNode.getIdent(), score);
 	}
 
+	@Override
+	public List<AssessmentEntry> getAssessmentData(CourseNode courseNode) {
+		return Collections.emptyList();
+	}
+
 	/**
 	 * @see org.olat.course.assessment.AssessmentManager#saveNodeAttempts(org.olat.course.nodes.CourseNode, org.olat.core.id.Identity, org.olat.core.id.Identity, java.lang.Integer)
 	 */
diff --git a/src/main/java/org/olat/course/site/ui/CourseSiteAdminController.java b/src/main/java/org/olat/course/site/ui/CourseSiteAdminController.java
index 298db11e9d5b26eb64bb3a16726d0608ee75bdbe..2abee7c14f99e0e4d614948b12174db91dcd752c 100644
--- a/src/main/java/org/olat/course/site/ui/CourseSiteAdminController.java
+++ b/src/main/java/org/olat/course/site/ui/CourseSiteAdminController.java
@@ -44,7 +44,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
@@ -109,9 +108,9 @@ public class CourseSiteAdminController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CSCols.title.i18nKey(), CSCols.title.ordinal()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, CSCols.courseId.i18nKey(), CSCols.courseId.ordinal(), false, null));
 		FlexiCellRenderer renderer = new StaticFlexiCellRenderer("openre", new TextFlexiCellRenderer());
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(CSCols.courseTitle.i18nKey(), CSCols.courseTitle.ordinal(), "openre", renderer));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translate("select"), "select"));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("remove", translate("remove"), "remove"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CSCols.courseTitle.i18nKey(), CSCols.courseTitle.ordinal(), "openre", renderer));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("remove", translate("remove"), "remove"));
 
 		String page = velocity_root + "/lang_options.html";
 		tableLayout = FormLayoutContainer.createCustomFormLayout("site.options.lang", getTranslator(), page);
diff --git a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
index be661066c35668eadeb29e26b34ff2adb8700828..4379802ce3a5e0b8cd91ba0742a3cfd6ecf0493a 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
@@ -51,7 +51,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableSearchEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
@@ -258,7 +257,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		}
 		if(isAdministrativeUser) {
 			FlexiCellRenderer renderer = new StaticFlexiCellRenderer(TABLE_ACTION_EDIT, new TextFlexiCellRenderer());
-			columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.username.i18n(), Cols.username.ordinal(), TABLE_ACTION_EDIT,
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.username.i18n(), Cols.username.ordinal(), TABLE_ACTION_EDIT,
 					true, Cols.username.name(), renderer));
 		}
 		
@@ -272,7 +271,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 				FlexiColumnModel col;
 				if(UserConstants.FIRSTNAME.equals(propName)
 						|| UserConstants.LASTNAME.equals(propName)) {
-					col = new StaticFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
+					col = new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey(),
 							colPos++, TABLE_ACTION_EDIT, true, propName,
 							new StaticFlexiCellRenderer(TABLE_ACTION_EDIT, new TextFlexiCellRenderer()));
 				} else {
diff --git a/src/main/java/org/olat/group/ui/main/BusinessGroupFlexiTableModel.java b/src/main/java/org/olat/group/ui/main/BusinessGroupFlexiTableModel.java
index 478f03eec83f4b847f834c39871d3a10d3348ea0..a4226ec335d0b0f670925860eb6c51ea20a1111c 100644
--- a/src/main/java/org/olat/group/ui/main/BusinessGroupFlexiTableModel.java
+++ b/src/main/java/org/olat/group/ui/main/BusinessGroupFlexiTableModel.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.util.Formatter;
@@ -74,7 +73,7 @@ public class BusinessGroupFlexiTableModel extends DefaultFlexiTableDataModel<BGT
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.mark.i18n(), Cols.mark.ordinal(),
 				true, Cols.mark.name()));
 		//group name
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
 				true, Cols.name.name(), new StaticFlexiCellRenderer(TABLE_ACTION_LAUNCH, new BusinessGroupNameCellRenderer())));
 		//id and reference
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.key.i18n(), Cols.key.ordinal(), true, Cols.key.name()));
@@ -103,10 +102,10 @@ public class BusinessGroupFlexiTableModel extends DefaultFlexiTableDataModel<BGT
 				true, Cols.role.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGRoleCellRenderer(translator.getLocale())));
 		
 		//actions
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.allowLeave.i18n(), Cols.allowLeave.ordinal(), TABLE_ACTION_LEAVE,
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.allowLeave.i18n(), Cols.allowLeave.ordinal(), TABLE_ACTION_LEAVE,
 				new BooleanCellRenderer(new StaticFlexiCellRenderer(translator.translate("table.header.leave"), TABLE_ACTION_LEAVE), null)));
 		if(delete) {
-			columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.allowDelete.i18n(), Cols.allowDelete.ordinal(), TABLE_ACTION_DELETE,
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.allowDelete.i18n(), Cols.allowDelete.ordinal(), TABLE_ACTION_DELETE,
 				new BooleanCellRenderer(new StaticFlexiCellRenderer(translator.translate("table.header.delete"), TABLE_ACTION_DELETE), null)));
 		}
 		
@@ -119,7 +118,7 @@ public class BusinessGroupFlexiTableModel extends DefaultFlexiTableDataModel<BGT
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.mark.i18n(), Cols.mark.ordinal(),
 				true, Cols.mark.name()));
 		//group name
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
 				true, Cols.name.name(), new StaticFlexiCellRenderer(TABLE_ACTION_LAUNCH, new BusinessGroupNameCellRenderer())));
 		//id and reference
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.key.i18n(), Cols.key.ordinal(), true, Cols.key.name()));
@@ -145,7 +144,7 @@ public class BusinessGroupFlexiTableModel extends DefaultFlexiTableDataModel<BGT
 				true, Cols.waitingListCount.name()));
 		
 		//actions
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translator.translate("select"), TABLE_ACTION_SELECT));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translator.translate("select"), TABLE_ACTION_SELECT));
 		return columnsModel;
 	}
 
diff --git a/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java
index 0bc11b54d49f58b4d37cc498b8d7f33ab442491a..322b297c9284f8066926bf71b8d88c9b27d1e21c 100644
--- a/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java
+++ b/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java
@@ -28,7 +28,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColum
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.group.BusinessGroup;
@@ -54,7 +53,7 @@ public class OpenBusinessGroupListController extends AbstractBusinessGroupListCo
 	protected FlexiTableColumnModel initColumnModel() {
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH,
 				true, Cols.name.name(), new StaticFlexiCellRenderer(TABLE_ACTION_LAUNCH, new BusinessGroupNameCellRenderer())));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.key.i18n(), Cols.key.ordinal(),
 				true, Cols.key.name()));
@@ -66,7 +65,7 @@ public class OpenBusinessGroupListController extends AbstractBusinessGroupListCo
 				false, null, FlexiColumnModel.ALIGNMENT_LEFT, new TextFlexiCellRenderer(EscapeMode.antisamy)));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.resources.i18n(), Cols.resources.ordinal(),
 				true, Cols.resources.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGResourcesCellRenderer(flc)));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.freePlaces.i18n(), Cols.freePlaces.ordinal(), TABLE_ACTION_LAUNCH,
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.freePlaces.i18n(), Cols.freePlaces.ordinal(), TABLE_ACTION_LAUNCH,
 				true, Cols.freePlaces.name(), new TextFlexiCellRenderer(EscapeMode.none)));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.accessTypes.i18n(), Cols.accessTypes.ordinal(),
 				true, Cols.accessTypes.name(), FlexiColumnModel.ALIGNMENT_LEFT, new BGAccessControlledCellRenderer()));
diff --git a/src/main/java/org/olat/ims/_spring/imsContext.xml b/src/main/java/org/olat/ims/_spring/imsContext.xml
index fc16b9ae262cccfb21409bfd7394718e9ea192f2..142f2764eabd0cfbc566588dbfa0a67d5188f795 100644
--- a/src/main/java/org/olat/ims/_spring/imsContext.xml
+++ b/src/main/java/org/olat/ims/_spring/imsContext.xml
@@ -8,10 +8,9 @@
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context.xsd">
   
-	<context:component-scan base-package="org.olat.ims.lti.manager,org.olat.ims.qti" />
+	<context:component-scan base-package="org.olat.ims.lti.manager,org.olat.ims.qti,org.olat.ims.qti21,uk.ac.ed.ph.jqtiplus" />
 
 	<import resource="classpath:/org/olat/ims/qti/_spring/qtiContext.xml"/>
-	<import resource="classpath:/org/olat/ims/qti21/_spring/qti21Context.xml"/>
 
 	<bean id="org.olat.ims.cp.CPManager" class="org.olat.ims.cp.CPManagerImpl"/> 
 	
diff --git a/src/main/java/org/olat/ims/qti/statistics/manager/QTIStatisticsManagerImpl.java b/src/main/java/org/olat/ims/qti/statistics/manager/QTIStatisticsManagerImpl.java
index 89be6c9e50332cea9389c1d18720e0a53c073af5..9decbec61d89f6a00374747d8e1a6aa42b7c1a41 100644
--- a/src/main/java/org/olat/ims/qti/statistics/manager/QTIStatisticsManagerImpl.java
+++ b/src/main/java/org/olat/ims/qti/statistics/manager/QTIStatisticsManagerImpl.java
@@ -30,7 +30,6 @@ import java.util.Map;
 import javax.persistence.TypedQuery;
 
 import org.olat.core.commons.persistence.DB;
-import org.olat.course.assessment.AssessmentManager;
 import org.olat.ims.qti.QTIResultManager;
 import org.olat.ims.qti.editor.beecom.objects.FIBResponse;
 import org.olat.ims.qti.editor.beecom.objects.Item;
@@ -48,7 +47,6 @@ import org.olat.ims.qti.statistics.model.StatisticKPrimOption;
 import org.olat.ims.qti.statistics.model.StatisticSurveyItem;
 import org.olat.ims.qti.statistics.model.StatisticSurveyItemResponse;
 import org.olat.ims.qti.statistics.model.StatisticsItem;
-import org.olat.properties.Property;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -76,9 +74,8 @@ public class QTIStatisticsManagerImpl implements QTIStatisticsManager {
 		}
 		
 		if(searchParams.isMayViewAllUsersAssessments()) {
-			sb.append(" and rset.identityKey in ( select p.identity.key from ").append(Property.class.getName()).append(" p ")
-			  .append("   where p.resourceTypeId=:resourceId and p.resourceTypeName='CourseModule'")
-			  .append(" and p.name in ('").append(AssessmentManager.SCORE).append("','").append(AssessmentManager.PASSED).append("')")
+			sb.append(" and rset.identityKey in (select nodeassessment.identity.key from coursenodeassessment nodeassessment ")
+			  .append("   where nodeassessment.courseEntry.key=rset.repositoryEntryKey and nodeassessment.courseNodeIdent=rset.olatResourceDetail")
 			  .append(" )");
 		}
 		return sb;
diff --git a/src/main/java/org/olat/ims/qti/statistics/model/QTIStatisticResultSet.java b/src/main/java/org/olat/ims/qti/statistics/model/QTIStatisticResultSet.java
index 5a091120721d407bc457e8469397f61d57b365ae..7a316b0209685a9cf235ab23d13f716567027eed 100644
--- a/src/main/java/org/olat/ims/qti/statistics/model/QTIStatisticResultSet.java
+++ b/src/main/java/org/olat/ims/qti/statistics/model/QTIStatisticResultSet.java
@@ -58,6 +58,8 @@ public class QTIStatisticResultSet implements CreateInfo, Persistable {
 	@Column(name="lastmodified", nullable=false, insertable=true, updatable=false)
 	private Date lastModified;
 
+	@Column(name="repositoryref_fk", nullable=false, insertable=true, updatable=false)
+	private Long repositoryEntryKey;
 	@Column(name="olatresource_fk", nullable=false, insertable=true, updatable=false)
 	private Long olatResource;
 	@Column(name="olatresourcedetail", nullable=false, insertable=true, updatable=false)
@@ -103,6 +105,13 @@ public class QTIStatisticResultSet implements CreateInfo, Persistable {
 		this.identityKey = identityKey;
 	}
 
+	public Long getRepositoryEntryKey() {
+		return repositoryEntryKey;
+	}
+
+	public void setRepositoryEntryKey(Long repositoryEntryKey) {
+		this.repositoryEntryKey = repositoryEntryKey;
+	}
 
 	public Long getOlatResource() {
 		return olatResource;
diff --git a/src/main/java/org/olat/ims/qti21/_spring/qti21Context.xml b/src/main/java/org/olat/ims/qti21/_spring/qti21Context.xml
deleted file mode 100644
index 1cbe50ad4b1cb43ccb4cc0b46737a6787af0d731..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/ims/qti21/_spring/qti21Context.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:context="http://www.springframework.org/schema/context" 
-	xsi:schemaLocation="
-  http://www.springframework.org/schema/beans 
-  http://www.springframework.org/schema/beans/spring-beans.xsd 
-  http://www.springframework.org/schema/context 
-  http://www.springframework.org/schema/context/spring-context.xsd">
-
-	<context:component-scan base-package="org.olat.ims.qti21,uk.ac.ed.ph.jqtiplus" />
-
-
-</beans>
\ No newline at end of file
diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
index e79ec405ebd25a66c6ecde85e160c34f2c9815f2..a8bfb7bbc94f5bdadac26b8b29f51ea1d0964b33 100644
--- a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
+++ b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
@@ -37,7 +37,6 @@ import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
 import org.olat.basesecurity.IdentityRef;
-import org.olat.core.commons.persistence.DB;
 import org.olat.core.gui.components.form.flexible.impl.MultipartFileInfos;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.OLATRuntimeException;
@@ -101,8 +100,6 @@ public class QTI21ServiceImpl implements QTI21Service {
 	
 	private static final OLog log = Tracing.createLoggerFor(QTI21ServiceImpl.class);
 	
-	@Autowired
-	private DB dbInstance;
 	@Autowired
 	private EventDAO eventDao;
 	@Autowired
diff --git a/src/main/java/org/olat/modules/assessment/AssessmentEntry.java b/src/main/java/org/olat/modules/assessment/AssessmentEntry.java
new file mode 100644
index 0000000000000000000000000000000000000000..373fcd6dbd507fffe0adafa618071bad86beaaf2
--- /dev/null
+++ b/src/main/java/org/olat/modules/assessment/AssessmentEntry.java
@@ -0,0 +1,86 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.assessment;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import org.olat.core.id.Identity;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * Initial date: 20.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface AssessmentEntry {
+	
+	public Long getKey();
+	
+	public Date getCreationDate();
+	
+	public Date getLastModified();
+	
+	public Long getAssessmentId();
+	
+	public void setAssessmentId(Long assessmentId);
+	
+	public Integer getAttempts();
+
+	public void setAttempts(Integer attempts);
+
+	public BigDecimal getScore();
+
+	public void setScore(BigDecimal score);
+
+	public Boolean getPassed();
+
+	public void setPassed(Boolean passed);
+
+	public Boolean getFullyAssessed();
+
+	public void setFullyAssessed(Boolean fullyAssessed);
+
+	public Double getCompletion();
+
+	public void setCompletion(Double completion);
+
+	public String getComment();
+
+	public void setComment(String comment);
+
+	public String getCoachComment();
+
+	public void setCoachComment(String coachComment);
+
+	public RepositoryEntry getRepositoryEntry();
+	
+	public String getSubIdent();
+	
+	/**
+	 * 
+	 * @return
+	 */
+	public RepositoryEntry getReferenceEntry();
+
+	public Identity getIdentity();
+
+}
diff --git a/src/main/java/org/olat/modules/assessment/AssessmentService.java b/src/main/java/org/olat/modules/assessment/AssessmentService.java
new file mode 100644
index 0000000000000000000000000000000000000000..6715ccdec598682cc7fea21b89e5dd7b9388445f
--- /dev/null
+++ b/src/main/java/org/olat/modules/assessment/AssessmentService.java
@@ -0,0 +1,30 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.assessment;
+
+/**
+ * 
+ * Initial date: 22.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface AssessmentService {
+
+}
diff --git a/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java b/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..9bc23b903cfb2f12cfb0e7b82d2d810ae4a242ca
--- /dev/null
+++ b/src/main/java/org/olat/modules/assessment/manager/AssessmentEntryDAO.java
@@ -0,0 +1,107 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.assessment.manager;
+
+import java.util.Date;
+import java.util.List;
+
+import org.olat.basesecurity.IdentityRef;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.modules.assessment.AssessmentEntry;
+import org.olat.modules.assessment.model.AssessmentEntryImpl;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryEntryRef;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 20.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class AssessmentEntryDAO {
+	
+	@Autowired
+	private DB dbInstance;
+	
+	public AssessmentEntry createCourseNodeAssessment(Identity assessedIdentity,
+			RepositoryEntry entry, String subIdent, RepositoryEntry referenceEntry) {
+		
+		AssessmentEntryImpl data = new AssessmentEntryImpl();
+		data.setCreationDate(new Date());
+		data.setLastModified(data.getCreationDate());
+		data.setIdentity(assessedIdentity);
+		data.setRepositoryEntry(entry);
+		data.setSubIdent(subIdent);
+		data.setReferenceEntry(referenceEntry);
+		dbInstance.getCurrentEntityManager().persist(data);
+		return data;
+	}
+	
+	public AssessmentEntry loadAssessmentEntryById(Long id) {
+		List<AssessmentEntry> nodeAssessment = dbInstance.getCurrentEntityManager()
+				.createNamedQuery("loadAssessmentEntryById", AssessmentEntry.class)
+				.setParameter("key", id)
+				.getResultList();
+		return nodeAssessment.isEmpty() ? null : nodeAssessment.get(0);
+	}
+
+	public AssessmentEntry loadAssessmentEntry(IdentityRef assessedIdentity, RepositoryEntryRef entry,
+			String subIdent) {
+		
+		List<AssessmentEntry> nodeAssessment = dbInstance.getCurrentEntityManager()
+				.createNamedQuery("loadAssessmentEntryByRepositoryEntryAndUser", AssessmentEntry.class)
+				.setParameter("repositoryEntryKey", entry.getKey())
+				.setParameter("identityKey", assessedIdentity.getKey())
+				.setParameter("subIdent", subIdent)
+				.getResultList();
+		return nodeAssessment.isEmpty() ? null : nodeAssessment.get(0);
+	}
+	
+	public AssessmentEntry updateCourseNodeAssessment(AssessmentEntry nodeAssessment) {
+		((AssessmentEntryImpl)nodeAssessment).setLastModified(new Date());
+		return dbInstance.getCurrentEntityManager().merge(nodeAssessment);
+	}
+	
+	public List<AssessmentEntry> loadAssessmentEntryBySubIdent(RepositoryEntryRef entry, String subIdent) {
+		return dbInstance.getCurrentEntityManager()
+				.createNamedQuery("loadAssessmentEntryByRepositoryEntryAndSubIdent", AssessmentEntry.class)
+				.setParameter("repositoryEntryKey", entry.getKey())
+				.setParameter("subIdent", subIdent)
+				.getResultList();
+	}
+	
+	public List<Identity> getAllIdentitiesWithAssessmentData(RepositoryEntryRef courseEntry) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select distinct data.identity from assessmententry data where data.repositoryEntry.key=:repositoryEntryKey");
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Identity.class)
+				.setParameter("repositoryEntryKey", courseEntry.getKey())
+				.getResultList();
+	}
+	
+
+	
+	
+
+}
diff --git a/src/main/java/org/olat/modules/assessment/model/AssessmentEntryImpl.java b/src/main/java/org/olat/modules/assessment/model/AssessmentEntryImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca5d5c3da9d4d700f3f6edb74ffe8fadd4e07400
--- /dev/null
+++ b/src/main/java/org/olat/modules/assessment/model/AssessmentEntryImpl.java
@@ -0,0 +1,257 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.assessment.model;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.olat.basesecurity.IdentityImpl;
+import org.olat.core.id.CreateInfo;
+import org.olat.core.id.Identity;
+import org.olat.core.id.ModifiedInfo;
+import org.olat.core.id.Persistable;
+import org.olat.modules.assessment.AssessmentEntry;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * Initial date: 20.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Entity(name="assessmententry")
+@Table(name="o_as_entry")
+@NamedQueries({
+	@NamedQuery(name="loadAssessmentEntryById", query="select data from assessmententry data where data.key=:key"),
+	@NamedQuery(name="loadAssessmentEntryByRepositoryEntryAndUser", query="select data from assessmententry data where data.repositoryEntry.key=:repositoryEntryKey and data.identity.key=:identityKey and data.subIdent=:subIdent"),
+	@NamedQuery(name="loadAssessmentEntryByRepositoryEntryAndSubIdent", query="select data from assessmententry data where data.repositoryEntry.key=:repositoryEntryKey and data.subIdent=:subIdent")
+	
+	
+})
+public class AssessmentEntryImpl implements Persistable, ModifiedInfo, CreateInfo, AssessmentEntry {
+	
+	private static final long serialVersionUID = 2934783777645549412L;
+
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
+	private Date lastModified;
+
+	@Column(name="a_attemtps", nullable=true, insertable=true, updatable=true)
+	private Integer attempts;
+	@Column(name="a_score", nullable=true, insertable=true, updatable=true)
+	private BigDecimal score;
+	@Column(name="a_passed", nullable=true, insertable=true, updatable=true)
+	private Boolean passed;
+
+	@Column(name="a_completion", nullable=true, insertable=true, updatable=true)
+	private Double completion;
+	
+	@Column(name="a_comment", nullable=true, insertable=true, updatable=true)
+	private String comment;
+	@Column(name="a_coach_comment", nullable=true, insertable=true, updatable=true)
+	private String coachComment;
+	
+	// fully passed and assessment id are only for onyx
+	@Column(name="a_fully_assessed", nullable=true, insertable=true, updatable=true)
+	private Boolean fullyAssessed;
+	@Column(name="a_assessment_id", nullable=true, insertable=true, updatable=true)
+	private Long assessmentId;
+	
+	@ManyToOne(targetEntity=RepositoryEntry.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_entry", nullable=false, insertable=true, updatable=false)
+    private RepositoryEntry repositoryEntry;
+	
+    @Column(name="a_subident", nullable=true, insertable=true, updatable=false)
+	private String subIdent;
+	
+	@ManyToOne(targetEntity=RepositoryEntry.class,fetch=FetchType.LAZY,optional=true)
+	@JoinColumn(name="fk_reference_entry", nullable=true, insertable=true, updatable=false)
+    private RepositoryEntry referenceEntry;
+
+	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_identity", nullable=false, insertable=true, updatable=false)
+    private Identity identity;
+	
+	
+	@Override
+	public Long getKey() {
+		return key;
+	}
+
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
+	@Override
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+
+	public Integer getAttempts() {
+		return attempts;
+	}
+
+	public void setAttempts(Integer attempts) {
+		this.attempts = attempts;
+	}
+
+	public BigDecimal getScore() {
+		return score;
+	}
+
+	public void setScore(BigDecimal score) {
+		this.score = score;
+	}
+
+	public Boolean getPassed() {
+		return passed;
+	}
+
+	public void setPassed(Boolean passed) {
+		this.passed = passed;
+	}
+
+	public Boolean getFullyAssessed() {
+		return fullyAssessed;
+	}
+
+	public void setFullyAssessed(Boolean fullyAssessed) {
+		this.fullyAssessed = fullyAssessed;
+	}
+
+	public Double getCompletion() {
+		return completion;
+	}
+
+	public void setCompletion(Double completion) {
+		this.completion = completion;
+	}
+
+	public String getComment() {
+		return comment;
+	}
+
+	public void setComment(String comment) {
+		this.comment = comment;
+	}
+
+	public String getCoachComment() {
+		return coachComment;
+	}
+
+	public void setCoachComment(String coachComment) {
+		this.coachComment = coachComment;
+	}
+
+	public Long getAssessmentId() {
+		return assessmentId;
+	}
+
+	public void setAssessmentId(Long assessmentId) {
+		this.assessmentId = assessmentId;
+	}
+
+	@Override
+	public RepositoryEntry getRepositoryEntry() {
+		return repositoryEntry;
+	}
+	
+	public void setRepositoryEntry(RepositoryEntry entry) {
+		this.repositoryEntry = entry;
+	}
+
+	@Override
+	public String getSubIdent() {
+		return subIdent;
+	}
+
+	public void setSubIdent(String subIdent) {
+		this.subIdent = subIdent;
+	}
+
+	public RepositoryEntry getReferenceEntry() {
+		return referenceEntry;
+	}
+
+	public void setReferenceEntry(RepositoryEntry referenceEntry) {
+		this.referenceEntry = referenceEntry;
+	}
+
+	public Identity getIdentity() {
+		return identity;
+	}
+
+	public void setIdentity(Identity identity) {
+		this.identity = identity;
+	}
+
+	@Override
+	public int hashCode() {
+		return key == null ? -864687 : key.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof AssessmentEntryImpl) {
+			AssessmentEntryImpl session = (AssessmentEntryImpl)obj;
+			return getKey() != null && getKey().equals(session.getKey());
+		}
+		return false;
+	}
+
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+}
diff --git a/src/main/java/org/olat/modules/qpool/ui/AbstractItemListController.java b/src/main/java/org/olat/modules/qpool/ui/AbstractItemListController.java
index a44508ae67f21d38bdd12eb178cc281ee3c8dccf..484b7b5056b7bb5443db752f313d237f476ab281 100644
--- a/src/main/java/org/olat/modules/qpool/ui/AbstractItemListController.java
+++ b/src/main/java/org/olat/modules/qpool/ui/AbstractItemListController.java
@@ -49,7 +49,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataSourceDelegate;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
@@ -122,7 +121,7 @@ public abstract class AbstractItemListController extends FormBasicController
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		//add the table
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("quickview", "<i class='o_icon o_icon_quickview'> </i>", "quick-view"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("quickview", "<i class='o_icon o_icon_quickview'> </i>", "quick-view"));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.mark.i18nKey(), Cols.mark.ordinal(), true, OrderBy.marks.name()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.editable.i18nKey(), Cols.editable.ordinal(),
 				false, null, FlexiColumnModel.ALIGNMENT_LEFT,
@@ -149,7 +148,7 @@ public abstract class AbstractItemListController extends FormBasicController
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.rating.i18nKey(), Cols.rating.ordinal(), true, OrderBy.rating.name()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.itemVersion.i18nKey(), Cols.itemVersion.ordinal(), true, OrderBy.itemVersion.name()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.status.i18nKey(), Cols.status.ordinal(), true, OrderBy.status.name()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("details", translate("details"), "select-item"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("details", translate("details"), "select-item"));
 		
 		model = new QuestionItemDataModel(columnsModel, this, getTranslator());
 		itemsTable = uifactory.addTableElement(getWindowControl(), "items", model, 50, true, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/modules/qpool/ui/CollectionListController.java b/src/main/java/org/olat/modules/qpool/ui/CollectionListController.java
index 4db0cb289f73c6a0c9a879b9ba59891061a258d3..e55689651a93d404109858ac71e7984873b504de 100644
--- a/src/main/java/org/olat/modules/qpool/ui/CollectionListController.java
+++ b/src/main/java/org/olat/modules/qpool/ui/CollectionListController.java
@@ -39,7 +39,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -87,7 +86,7 @@ public class CollectionListController extends FormBasicController {
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("collection.name", 0));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("collection.creationDate", 1));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translate("select"), "select-coll"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select-coll"));
 		
 		model = new CollectionsDataModel(colls, columnsModel);
 		collectionsTable = uifactory.addTableElement(getWindowControl(), "collections", model, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/modules/qpool/ui/PoolsController.java b/src/main/java/org/olat/modules/qpool/ui/PoolsController.java
index f56cdcaf7506d14fa363bb4447277792b348968a..e43344b9e7651b5fb7abce5fa6652255eb3c149f 100644
--- a/src/main/java/org/olat/modules/qpool/ui/PoolsController.java
+++ b/src/main/java/org/olat/modules/qpool/ui/PoolsController.java
@@ -43,7 +43,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.table.TableDataModel;
 import org.olat.core.gui.control.Controller;
@@ -109,7 +108,7 @@ public class PoolsController extends FormBasicController {
 						new CSSIconFlexiCellRenderer("o_private"))
 		));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.name.i18nKey(), Cols.name.ordinal(), true, "name"));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("select", translate("select"), "select-pool"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select-pool"));
 
 		model = new PoolDataModel(columnsModel, getTranslator());
 		poolTable = uifactory.addTableElement(getWindowControl(), "pools", model, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/PoolsAdminController.java b/src/main/java/org/olat/modules/qpool/ui/admin/PoolsAdminController.java
index 7449b12bf5bbcc8942ca1fb4609c0aa9f1226671..8964277fc05c9759df73bbbc72c94fce6c75362b 100644
--- a/src/main/java/org/olat/modules/qpool/ui/admin/PoolsAdminController.java
+++ b/src/main/java/org/olat/modules/qpool/ui/admin/PoolsAdminController.java
@@ -44,7 +44,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.table.TableDataModel;
 import org.olat.core.gui.control.Controller;
@@ -108,9 +107,9 @@ public class PoolsAdminController extends FormBasicController {
 						new CSSIconFlexiCellRenderer("o_icon_pool_private"))
 		));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.name.i18nKey(), Cols.name.ordinal(), true, "name"));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("edit", translate("edit"), "edit-pool"));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("pool.owners", translate("pool.owners"), "owners-pool"));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", translate("delete"), "delete-pool"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate("edit"), "edit-pool"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("pool.owners", translate("pool.owners"), "owners-pool"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete-pool"));
 
 		model = new PoolDataModel(columnsModel, getTranslator());
 		poolTable = uifactory.addTableElement(getWindowControl(), "pools", model, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextsAdminController.java b/src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextsAdminController.java
index dd8314430bd377a03639cc10f828f97c5f9914c2..abd77fd2dac1e6ca4ef127f7e85a22357d79b444 100644
--- a/src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextsAdminController.java
+++ b/src/main/java/org/olat/modules/qpool/ui/admin/QEducationalContextsAdminController.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.table.TableDataModel;
@@ -100,9 +99,9 @@ public class QEducationalContextsAdminController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.id.i18nKey(), Cols.id.ordinal(), true, "key"));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.level.i18nKey(), Cols.level.ordinal(), true, "level"));
 		FlexiCellRenderer renderer = new StaticFlexiCellRenderer("translate", new TextFlexiCellRenderer());
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.levelI18n.i18nKey(), Cols.levelI18n.ordinal(), "translate", renderer));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.levelI18n.i18nKey(), Cols.levelI18n.ordinal(), "translate", renderer));
 		FlexiCellRenderer delRenderer = new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("delete"), "delete-level"), null);
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", Cols.deletable.ordinal(), "delete-level", delRenderer));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", Cols.deletable.ordinal(), "delete-level", delRenderer));
 
 		model = new LevelDataModel(columnsModel);
 		tableEl = uifactory.addTableElement(getWindowControl(), "levels", model, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/QItemTypesAdminController.java b/src/main/java/org/olat/modules/qpool/ui/admin/QItemTypesAdminController.java
index e13ba5480d78f0fd2b126b3056059542537a9f34..642f79fda562daf1438017ead6024a7789309bb4 100644
--- a/src/main/java/org/olat/modules/qpool/ui/admin/QItemTypesAdminController.java
+++ b/src/main/java/org/olat/modules/qpool/ui/admin/QItemTypesAdminController.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.table.TableDataModel;
@@ -100,9 +99,9 @@ public class QItemTypesAdminController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.id.i18nKey(), Cols.id.ordinal(), true, "key"));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.type.i18nKey(), Cols.type.ordinal(), true, "name"));
 		FlexiCellRenderer renderer = new StaticFlexiCellRenderer("translate", new TextFlexiCellRenderer());
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.typeI18n.i18nKey(), Cols.typeI18n.ordinal(), "translate", renderer));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.typeI18n.i18nKey(), Cols.typeI18n.ordinal(), "translate", renderer));
 		FlexiCellRenderer delRenderer = new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("delete"), "delete-type"), null);
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", Cols.deletable.ordinal(), "delete-type", delRenderer));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", Cols.deletable.ordinal(), "delete-type", delRenderer));
 
 		model = new QItemTypeDataModel(columnsModel);
 		tableEl = uifactory.addTableElement(getWindowControl(), "types", model, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/modules/qpool/ui/admin/QLicensesAdminController.java b/src/main/java/org/olat/modules/qpool/ui/admin/QLicensesAdminController.java
index 1041d9cd247edbc7e49361175d6653c3213fd819..b6066fe115b34b79b265a9bac9402ab71c700653 100644
--- a/src/main/java/org/olat/modules/qpool/ui/admin/QLicensesAdminController.java
+++ b/src/main/java/org/olat/modules/qpool/ui/admin/QLicensesAdminController.java
@@ -39,7 +39,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.table.TableDataModel;
 import org.olat.core.gui.control.Controller;
@@ -94,7 +93,7 @@ public class QLicensesAdminController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.id.i18nKey(), Cols.id.ordinal(), true, "key"));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.licenseKey.i18nKey(), Cols.licenseKey.ordinal(), true, "licenseKey"));
 		FlexiCellRenderer delRenderer = new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("delete"), "delete-license"), null);
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", Cols.deletable.ordinal(), "delete-license", delRenderer));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", Cols.deletable.ordinal(), "delete-license", delRenderer));
 
 		model = new QItemTypeDataModel(columnsModel);
 		tableEl = uifactory.addTableElement(getWindowControl(), "licenses", model, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java b/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java
index 4021208046e37fbf669e9cf821cee9c9a24434fc..888e40f279ad3e2d5ef2443970686f159cd1965f 100755
--- a/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java
+++ b/src/main/java/org/olat/portfolio/manager/EPFrontendManager.java
@@ -46,7 +46,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentManager;
-import org.olat.course.assessment.AssessmentNotificationsHandler;
+import org.olat.course.assessment.manager.AssessmentNotificationsHandler;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.course.run.userview.UserCourseEnvironmentImpl;
diff --git a/src/main/java/org/olat/repository/ui/LifecycleAdminController.java b/src/main/java/org/olat/repository/ui/LifecycleAdminController.java
index c805505595fd3037d9015b0b4b0dbe4978710114..df3515949583419c846826ae06d5531be7bccee1 100644
--- a/src/main/java/org/olat/repository/ui/LifecycleAdminController.java
+++ b/src/main/java/org/olat/repository/ui/LifecycleAdminController.java
@@ -37,7 +37,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -89,8 +88,8 @@ public class LifecycleAdminController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(LCCols.validTo.i18nKey(), LCCols.validTo.ordinal()));
 
 		FlexiCellRenderer delRenderer = new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("delete"), "delete-cycle"), null);
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("delete", LCCols.delete.ordinal(), "delete-cycle", delRenderer));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("edit", translate(LCCols.edit.i18nKey()), "edit-lifecycle"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", LCCols.delete.ordinal(), "delete-cycle", delRenderer));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate(LCCols.edit.i18nKey()), "edit-lifecycle"));
 
 		model = new LifecycleDataModel(columnsModel);
 		tableEl = uifactory.addTableElement(getWindowControl(), "cycles", model, getTranslator(), formLayout);
diff --git a/src/main/java/org/olat/repository/ui/author/AuthorListController.java b/src/main/java/org/olat/repository/ui/author/AuthorListController.java
index 86dc47a69d3e8ca562ea7a185cbef4a92b2d3f8f..b2e9853672cf97d569daeb55bbb15c6e2fea58e4 100644
--- a/src/main/java/org/olat/repository/ui/author/AuthorListController.java
+++ b/src/main/java/org/olat/repository/ui/author/AuthorListController.java
@@ -55,7 +55,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
@@ -246,7 +245,7 @@ public class AuthorListController extends FormBasicController implements Activat
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.type.i18nKey(), Cols.type.ordinal(), true, OrderBy.type.name(),
 				FlexiColumnModel.ALIGNMENT_LEFT, new TypeRenderer()));
 		FlexiCellRenderer renderer = new StaticFlexiCellRenderer("select", new TextFlexiCellRenderer());
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.displayName.i18nKey(), Cols.displayName.ordinal(), "select",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.displayName.i18nKey(), Cols.displayName.ordinal(), "select",
 				true, OrderBy.displayname.name(), renderer));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.authors.i18nKey(), Cols.authors.ordinal(),
 				true, OrderBy.authors.name()));
@@ -274,10 +273,10 @@ public class AuthorListController extends FormBasicController implements Activat
 				true, OrderBy.creationDate.name()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.lastUsage.i18nKey(), Cols.lastUsage.ordinal(),
 				true, OrderBy.lastUsage.name()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.detailsSupported.i18nKey(), Cols.detailsSupported.ordinal(), "details",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.detailsSupported.i18nKey(), Cols.detailsSupported.ordinal(), "details",
 				new StaticFlexiCellRenderer("", "details", "o_icon o_icon-lg o_icon_details", translate("details"))));
 		if(hasAuthorRight) {
-			columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.editionSupported.i18nKey(), Cols.editionSupported.ordinal(), "edit",
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.editionSupported.i18nKey(), Cols.editionSupported.ordinal(), "edit",
 				new BooleanCellRenderer(new StaticFlexiCellRenderer("", "edit", "o_icon o_icon-lg o_icon_edit", translate("edit")), null)));
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.tools.i18nKey(), Cols.tools.ordinal()));
 		}
diff --git a/src/main/java/org/olat/repository/ui/author/CatalogSettingsController.java b/src/main/java/org/olat/repository/ui/author/CatalogSettingsController.java
index 53759b6edf5b8a4b356d1f9b585c20ec276c9b83..fa051cb5a532b8da234fb641f1ca6a6886f14dbb 100644
--- a/src/main/java/org/olat/repository/ui/author/CatalogSettingsController.java
+++ b/src/main/java/org/olat/repository/ui/author/CatalogSettingsController.java
@@ -34,7 +34,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFle
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
@@ -94,7 +93,7 @@ public class CatalogSettingsController extends FormBasicController {
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("catalog.path", 0));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel("remove", translate("remove"), "remove"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("remove", translate("remove"), "remove"));
 		
 		List<CatalogEntry> catalogEntries = catalogManager.getCatalogCategoriesFor(entry);
 		model = new CategoriesListModel(catalogEntries, columnsModel);
diff --git a/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java b/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java
index 09df1e365dadc4e846ebc10842253c40663f9d05..759291a975e7a94dc7ebac2b40014b802cacf6c7 100644
--- a/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java
+++ b/src/main/java/org/olat/repository/ui/catalog/CatalogNodeManagerController.java
@@ -47,7 +47,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
@@ -221,7 +220,7 @@ public class CatalogNodeManagerController extends FormBasicController implements
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, Cols.type.i18nKey(), Cols.type.ordinal(), true, OrderBy.type.name(),
 				FlexiColumnModel.ALIGNMENT_LEFT, new TypeRenderer()));
 		FlexiCellRenderer renderer = new StaticFlexiCellRenderer("select", new TextFlexiCellRenderer());
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.displayName.i18nKey(), Cols.displayName.ordinal(), "select",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.displayName.i18nKey(), Cols.displayName.ordinal(), "select",
 				true, OrderBy.displayname.name(), renderer));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.authors.i18nKey(), Cols.authors.ordinal(),
 				true, OrderBy.authors.name()));
@@ -245,9 +244,9 @@ public class CatalogNodeManagerController extends FormBasicController implements
 				true, OrderBy.ac.name(), FlexiColumnModel.ALIGNMENT_LEFT, new ACRenderer()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.creationDate.i18nKey(), Cols.creationDate.ordinal(),
 				true, OrderBy.creationDate.name()));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.delete.i18nKey(), translate(Cols.delete.i18nKey()), "delete"));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.move.i18nKey(), translate(Cols.move.i18nKey()), "move"));
-		columnsModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.detailsSupported.i18nKey(), Cols.detailsSupported.ordinal(), "details",
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.delete.i18nKey(), translate(Cols.delete.i18nKey()), "delete"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.move.i18nKey(), translate(Cols.move.i18nKey()), "move"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.detailsSupported.i18nKey(), Cols.detailsSupported.ordinal(), "details",
 				new StaticFlexiCellRenderer("", "details", "o_icon o_icon-lg o_icon_details", translate("details"))));
 		
 		entriesModel = new CatalogEntryRowModel(columnsModel);
diff --git a/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java b/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
index 80634f5b536e608feb0ef2376943a9923c12de97..179c2290e97df3d6e8e5cac796176015e8d9838f 100644
--- a/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
@@ -50,7 +50,6 @@ import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.core.CoreSpringFactory;
-import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.logging.OLog;
@@ -61,7 +60,6 @@ import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.IQTESTCourseNode;
-import org.olat.course.properties.CoursePropertyManager;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.course.run.scoring.ScoreAccounting;
 import org.olat.course.run.scoring.ScoreEvaluation;
@@ -83,7 +81,6 @@ import org.olat.ims.qti.process.AssessmentFactory;
 import org.olat.ims.qti.process.AssessmentInstance;
 import org.olat.modules.ModuleConfiguration;
 import org.olat.modules.iq.IQManager;
-import org.olat.properties.Property;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryService;
@@ -555,30 +552,8 @@ public class CourseAssessmentWebService {
 	}
 	
 	private Date getLastModificationDate(Identity assessedIdentity, ICourse course, CourseNode courseNode) {
-		//try to load the exact score prpoerty saved on the DB
-		
-		final CoursePropertyManager cpm = course.getCourseEnvironment().getCoursePropertyManager();
-		Property scoreProperty = cpm.findCourseNodeProperty(courseNode, assessedIdentity, null, AssessmentManager.SCORE);
-		if(scoreProperty != null) {
-			return scoreProperty.getLastModified();
-		}
-	  
-		//last change in course
-		StringBuilder sb = new StringBuilder();
-		sb.append("select max(p.lastModified) from ").append(Property.class.getName()).append(" as p where")
-			.append(" p.resourceTypeName = :restypename and p.resourceTypeId = :restypeid")
-			.append(" and p.name = '").append(AssessmentManager.SCORE).append("'")
-			.append(" and p.identity = :id");
-		List<Date> properties = DBFactory.getInstance().getCurrentEntityManager()
-				.createQuery(sb.toString(), Date.class)
-				.setParameter("restypename", course.getResourceableTypeName())
-				.setParameter("restypeid", course.getResourceableId().longValue())
-				.setParameter("id", assessedIdentity)
-				.getResultList();
-		if(!properties.isEmpty()) {
-			return properties.get(0);
-		}
-		return null;
+		AssessmentManager am = course.getCourseEnvironment().getAssessmentManager();
+		return am.getScoreLastModifiedDate(courseNode, assessedIdentity);
 	}
 
 	private List<Identity> loadUsers(ICourse course) {
diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_11_0_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_11_0_0.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3ebb73a8985ebc2120daa63599a0e4514c708a0
--- /dev/null
+++ b/src/main/java/org/olat/upgrade/OLATUpgrade_11_0_0.java
@@ -0,0 +1,595 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.upgrade;
+
+import static org.olat.upgrade.legacy.NewCachePersistingAssessmentManager.ASSESSMENT_ID;
+import static org.olat.upgrade.legacy.NewCachePersistingAssessmentManager.ATTEMPTS;
+import static org.olat.upgrade.legacy.NewCachePersistingAssessmentManager.COACH_COMMENT;
+import static org.olat.upgrade.legacy.NewCachePersistingAssessmentManager.COMMENT;
+import static org.olat.upgrade.legacy.NewCachePersistingAssessmentManager.FULLY_ASSESSED;
+import static org.olat.upgrade.legacy.NewCachePersistingAssessmentManager.PASSED;
+import static org.olat.upgrade.legacy.NewCachePersistingAssessmentManager.SCORE;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.olat.basesecurity.GroupRoles;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.persistence.DBFactory;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.cache.CacheWrapper;
+import org.olat.course.CourseFactory;
+import org.olat.course.ICourse;
+import org.olat.course.nodes.CourseNode;
+import org.olat.course.tree.CourseEditorTreeNode;
+import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupService;
+import org.olat.group.model.SearchBusinessGroupParams;
+import org.olat.modules.assessment.AssessmentEntry;
+import org.olat.modules.assessment.model.AssessmentEntryImpl;
+import org.olat.properties.Property;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.repository.RepositoryService;
+import org.olat.repository.model.SearchRepositoryEntryParameters;
+import org.olat.upgrade.legacy.NewCacheKey;
+import org.olat.upgrade.legacy.NewCachePersistingAssessmentManager;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 27.03.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class OLATUpgrade_11_0_0 extends OLATUpgrade {
+	
+	private static final int BATCH_SIZE = 50;
+	private static final String ASSESSMENT_DATAS = "ASSESSMENT PROPERTY TABLE";
+	private static final String VERSION = "OLAT_11.0.0";
+
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private RepositoryManager repositoryManager;
+	@Autowired
+	private BusinessGroupService businessGroupService;
+	@Autowired
+	private RepositoryService repositoryService;
+
+	public OLATUpgrade_11_0_0() {
+		super();
+	}
+
+	@Override
+	public String getVersion() {
+		return VERSION;
+	}
+	
+	@Override
+	public boolean doPreSystemInitUpgrade(UpgradeManager upgradeManager) {
+		return false;
+	}
+
+	@Override
+	public boolean doPostSystemInitUpgrade(UpgradeManager upgradeManager) {
+		UpgradeHistoryData uhd = upgradeManager.getUpgradesHistory(VERSION);
+		if (uhd == null) {
+			// has never been called, initialize
+			uhd = new UpgradeHistoryData();
+		} else if (uhd.isInstallationComplete()) {
+			return false;
+		}
+		
+		boolean allOk = true;
+		allOk &= upgradeAssessmentPropertyTable(upgradeManager, uhd);
+
+		uhd.setInstallationComplete(allOk);
+		upgradeManager.setUpgradesHistory(uhd, VERSION);
+		if(allOk) {
+			log.audit("Finished OLATUpgrade_11_0_0 successfully!");
+		} else {
+			log.audit("OLATUpgrade_11_0_0 not finished, try to restart OpenOLAT!");
+		}
+		return allOk;
+	}
+	
+	private boolean upgradeAssessmentPropertyTable(UpgradeManager upgradeManager, UpgradeHistoryData uhd) {
+		boolean allOk = true;
+		if (!uhd.getBooleanDataValue(ASSESSMENT_DATAS)) {
+			int counter = 0;
+			final Roles roles = new Roles(true, true, true, true, false, true, false);
+			final SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters();
+			params.setRoles(roles);
+			params.setResourceTypes(Collections.singletonList("CourseModule"));
+			
+			List<RepositoryEntry> courses;
+			do {
+				courses = repositoryManager.genericANDQueryWithRolesRestriction(params, counter, 50, true);
+				for(RepositoryEntry course:courses) {
+					allOk &= processCourseAssessmentData(course); 
+				}
+				counter += courses.size();
+				log.audit("Assessment data migration processed: " + courses.size() + ", total processed (" + counter + ")");
+				dbInstance.commitAndCloseSession();
+			} while(courses.size() == BATCH_SIZE);
+			uhd.setBooleanDataValue(ASSESSMENT_DATAS, allOk);
+			upgradeManager.setUpgradesHistory(uhd, VERSION);
+		}
+		return allOk;
+	}
+	
+	// select count(*) from o_property where name in ('SCORE','PASSED','ATTEMPTS','COMMENT','COACH_COMMENT','ASSESSMENT_ID','FULLY_ASSESSED');
+	private boolean processCourseAssessmentData(RepositoryEntry courseEntry) {
+		Long courseResourceId = courseEntry.getOlatResource().getResourceableId();
+		
+		//load already migrated data
+		List<AssessmentEntryImpl> currentNodeAssessmentList = loadAssessmentEntries(courseEntry);
+		Map<AssessmentDataKey,AssessmentEntryImpl> curentNodeAssessmentMap = new HashMap<>();
+		for(AssessmentEntryImpl currentNodeAssessment:currentNodeAssessmentList) {
+			AssessmentDataKey key = new AssessmentDataKey(currentNodeAssessment.getIdentity(), courseResourceId, currentNodeAssessment.getSubIdent());
+			curentNodeAssessmentMap.put(key, currentNodeAssessment);
+		}
+
+		Map<AssessmentDataKey,AssessmentEntryImpl> nodeAssessmentMap = new HashMap<>();
+		
+		List<Property> courseProperties = loadAssessmentProperties(courseEntry);
+		for(Property property:courseProperties) {
+			String propertyCategory = property.getCategory();
+			if(StringHelper.containsNonWhitespace(propertyCategory)) {
+				int nodeIdentIndex = propertyCategory.indexOf("::");
+				if(nodeIdentIndex > 0) {
+					String nodeIdent = propertyCategory.substring(propertyCategory.indexOf("::") + 2);
+					AssessmentDataKey key = new AssessmentDataKey(property.getIdentity(), property.getResourceTypeId(), nodeIdent);
+					if(curentNodeAssessmentMap.containsKey(key)) {
+						continue;
+					}
+					
+					AssessmentEntryImpl nodeAssessment;
+					if(nodeAssessmentMap.containsKey(key)) {
+						nodeAssessment = nodeAssessmentMap.get(key);
+						if(nodeAssessment.getCreationDate().after(property.getCreationDate())) {
+							nodeAssessment.setCreationDate(property.getCreationDate());
+						}
+						
+						if(nodeAssessment.getLastModified().before(property.getLastModified())) {
+							nodeAssessment.setLastModified(property.getLastModified());
+						}
+					} else {
+						nodeAssessment = createAssessmentEntry(property, courseEntry, nodeIdent, courseEntry);
+					}
+					copyAssessmentProperty(property, nodeAssessment);
+					nodeAssessmentMap.put(key, nodeAssessment);	
+				}
+			}	
+		}
+		
+		int count = 0;
+		for(AssessmentEntryImpl courseNodeAssessment:nodeAssessmentMap.values()) {
+			dbInstance.getCurrentEntityManager().persist(courseNodeAssessment);
+			if(++count % 50 == 0) {
+				dbInstance.commit();
+			}
+		}
+		dbInstance.commitAndCloseSession();
+		
+		return verifyCourseAssessmentData(courseEntry);
+	}
+	
+	/**
+	 * The method compare the content of the cache used in assessment tool
+	 * with the migrated values and vice versa.
+	 * 
+	 * @param courseEntry
+	 * @return
+	 */
+	private boolean verifyCourseAssessmentData(RepositoryEntry courseEntry) {
+		//load the cache and fill it with the same amount of datas as in assessment tool
+		ICourse course = CourseFactory.loadCourse(courseEntry.getOlatResource());
+		StaticCacheWrapper cache = new StaticCacheWrapper();
+		NewCachePersistingAssessmentManager assessmentManager = new NewCachePersistingAssessmentManager(course, cache);
+		List<Identity> assessableIdentities = getAllAssessableIdentities(courseEntry);
+		assessmentManager.preloadCache(assessableIdentities);
+		dbInstance.commitAndCloseSession();
+		
+		Set<Identity> assessableIdentitySet = new HashSet<>(assessableIdentities);
+		List<AssessmentEntryImpl> nodeAssessments = loadAssessmentEntries(courseEntry);
+		Map<AssessmentDataKey, AssessmentEntryImpl> nodeAssessmentMap = new HashMap<>();
+		for(AssessmentEntryImpl nodeAssessment:nodeAssessments) {
+			if(!assessableIdentitySet.contains(nodeAssessment.getIdentity())) {
+				assessmentManager.preloadCache(nodeAssessment.getIdentity());
+			}
+			if(nodeAssessment.getIdentity() != null && nodeAssessment.getRepositoryEntry() != null
+					&& nodeAssessment.getRepositoryEntry().getOlatResource() != null) {
+				nodeAssessmentMap.put(new AssessmentDataKey(nodeAssessment), nodeAssessment);
+			}
+		}
+		dbInstance.commitAndCloseSession();
+		
+		//compare the value in CourseNodeAssessment with the content of the cache
+		boolean allOk = true;
+		for(AssessmentEntryImpl nodeAssessment:nodeAssessments) {
+			allOk &= compareCourseNodeAssessment(nodeAssessment, assessmentManager, course, courseEntry);
+		}
+		dbInstance.commitAndCloseSession();
+		
+		//compare the content of the cache with the CourseNodeAssessments
+		for(NewCacheKey cacheKey:cache.getKeys()) {
+			Map<String,Serializable> dataMap = cache.get(cacheKey);
+			Long identityKey = cacheKey.getIdentityKey();
+			for(Map.Entry<String, Serializable> data:dataMap.entrySet()) {
+				String key = data.getKey();
+				int index = key.indexOf("_");
+				if(index > 0 && !key.equals("LAST_MODIFIED")) {
+					String nodeIdent = key.substring(0, index);
+					String dataType = key.substring(index + 1);
+					
+					AssessmentDataKey assessmentDataKey = new AssessmentDataKey(identityKey, course.getResourceableId(), nodeIdent);
+					AssessmentEntryImpl nodeAssessment = nodeAssessmentMap.get(assessmentDataKey);
+					allOk &= compareProperty(dataType, data.getValue(), nodeAssessment, courseEntry, nodeIdent, identityKey);
+				}
+			}
+		}
+		dbInstance.commitAndCloseSession();
+		
+		if(!allOk) {
+			log.error("Critical error during course verification: " + courseEntry.getDisplayname() + "(" + courseEntry.getKey() + ")");
+		}
+		return allOk;
+	}
+	
+	private boolean compareProperty(String dataType, Serializable value, AssessmentEntryImpl nodeAssessment, RepositoryEntry courseEntry, String nodeIdent, Long identityKey) {
+		boolean allOk = true;
+		if(nodeAssessment == null) {
+			log.audit("ERROR nodeAssessment not found: " + getErrorAt(courseEntry, nodeIdent, identityKey));
+			allOk = false;
+		} else if(ATTEMPTS.equals(dataType)) {
+			if((value == null && nodeAssessment.getAttempts() == null) ||
+					(value != null && nodeAssessment.getAttempts() != null && value.equals(nodeAssessment.getAttempts()))) {
+				//ok
+			} else {
+				log.audit("ERROR number of attempts: " + value + " / " + nodeAssessment.getAttempts() + getErrorAt(courseEntry, nodeIdent, identityKey));
+				allOk &= false;
+			}
+		} else if(PASSED.equals(dataType)) {
+			if((value == null && nodeAssessment.getPassed() == null) ||
+					(value != null && nodeAssessment.getPassed() != null && value.equals(nodeAssessment.getPassed()))) {
+				//ok
+			} else {
+				log.audit("ERROR passed: " + value + " / " + nodeAssessment.getPassed() + getErrorAt(courseEntry, nodeIdent, identityKey));
+				allOk &= false;
+			}
+		} else if(FULLY_ASSESSED.equals(dataType)) {
+			if((value == null && nodeAssessment.getFullyAssessed() == null) ||
+					(value != null && nodeAssessment.getFullyAssessed() != null && value.equals(nodeAssessment.getFullyAssessed()))) {
+				//ok
+			} else {
+				log.audit("ERROR fullyAssessed: " + value + " / " + nodeAssessment.getFullyAssessed() + getErrorAt(courseEntry, nodeIdent, identityKey));
+				allOk &= false;
+			}
+		} else if(SCORE.equals(dataType)) {
+			if((value == null && nodeAssessment.getScore() == null) ||
+					(value instanceof Float && nodeAssessment.getScore() != null && Math.abs(((Float)value).floatValue() - nodeAssessment.getScore().floatValue()) < 0.00001f)) {
+				//ok
+			} else {
+				log.audit("ERROR score: " + value + " / " + nodeAssessment.getScore() + getErrorAt(courseEntry, nodeIdent, identityKey));
+				allOk &= false;
+			}
+		}
+		return allOk;
+	}
+
+	private String getErrorAt(RepositoryEntry courseEntry, String nodeIdent, Long identityKey) {
+		return " at course : " + courseEntry.getDisplayname() + " (" + courseEntry.getKey() + ")"
+			+ " at node: " + nodeIdent + " for identity: " + identityKey;
+	}
+	
+	private boolean compareCourseNodeAssessment(AssessmentEntryImpl entry, NewCachePersistingAssessmentManager assessmentManager,
+			ICourse course, RepositoryEntry courseEntry) {
+		CourseNode node = course.getRunStructure().getNode(entry.getSubIdent());
+		if(node == null) {
+			CourseEditorTreeNode editorNode = course.getEditorTreeModel().getCourseEditorNodeById(entry.getSubIdent());
+			if(editorNode != null) {
+				node = editorNode.getCourseNode();
+			}
+		}
+		
+		boolean allOk = true;
+		if(node != null) {
+			Identity assessedIdentity = entry.getIdentity();
+			
+			Integer attempts = assessmentManager.getNodeAttempts(node, assessedIdentity);
+			if((attempts == null && entry.getAttempts() == null) ||
+					(attempts != null && entry.getAttempts() != null && attempts.equals(entry.getAttempts()))) {
+				//ok
+			} else {
+				log.audit("ERROR number of attempts: " + attempts + " / " + entry.getAttempts() + getErrorAt(courseEntry, node));
+				allOk &= false;
+			}
+			
+			Boolean passed = assessmentManager.getNodePassed(node, assessedIdentity);
+			if((passed == null && entry.getPassed() == null) ||
+					(passed != null && entry.getPassed() != null && passed.equals(entry.getPassed()))) {
+				//ok
+			} else {
+				log.audit("ERROR passed: " + passed + " / " + entry.getPassed() + getErrorAt(courseEntry, node));
+				allOk &= false;
+			}
+
+			Boolean fullyAssessed = assessmentManager.getNodeFullyAssessed(node, assessedIdentity);
+			if((fullyAssessed == null && entry.getFullyAssessed() == null) ||
+					(fullyAssessed != null && entry.getFullyAssessed() != null && fullyAssessed.equals(entry.getFullyAssessed()))) {
+				//ok
+			} else {
+				log.audit("ERROR fullyAssessed: " + fullyAssessed + " / " + entry.getFullyAssessed() + getErrorAt(courseEntry, node));
+				allOk &= false;
+			}
+
+			Float score = assessmentManager.getNodeScore(node, assessedIdentity);
+			if((score == null && entry.getScore() == null) ||
+					(score != null && entry.getScore() != null && Math.abs(score.floatValue() - entry.getScore().floatValue()) < 0.00001f)) {
+				//ok
+			} else {
+				log.audit("ERROR score: " + score + " / " + entry.getScore() + getErrorAt(courseEntry, node));
+				allOk &= false;
+			}
+		}
+		return allOk;
+	}
+	
+	private String getErrorAt(RepositoryEntry courseEntry, CourseNode courseNode) {
+		return " at course : " + courseEntry.getDisplayname() + " (" + courseEntry.getKey() + ")"
+			+ " at node: " + courseNode.getShortTitle() + " (" + courseNode.getIdent() + ")";
+	}
+	
+	/**
+	 * Return the same amount of user as in the assessment tool.
+	 * @param entry
+	 * @return
+	 */
+	private List<Identity> getAllAssessableIdentities(RepositoryEntry entry) {
+		Set<Identity> duplicateKiller = new HashSet<>();
+		List<Identity> assessableIdentities = new ArrayList<>();
+		
+		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+		List<BusinessGroup> coachedGroups = businessGroupService.findBusinessGroups(params, entry, 0, -1);
+		
+		List<Identity> participants = businessGroupService.getMembers(coachedGroups, GroupRoles.participant.name());
+		for(Identity participant:participants) {
+			if(!duplicateKiller.contains(participant)) {
+				assessableIdentities.add(participant);
+				duplicateKiller.add(participant);
+			}
+		}
+		
+
+		List<Identity> courseParticipants = repositoryService.getMembers(entry, GroupRoles.participant.name());
+		for(Identity participant:courseParticipants) {
+			if(!duplicateKiller.contains(participant)) {
+				assessableIdentities.add(participant);
+				duplicateKiller.add(participant);
+			}
+		}
+
+		ICourse course = CourseFactory.loadCourse(entry.getOlatResource());
+		List<Identity> assessedUsers = getAllIdentitiesWithCourseAssessmentData(course.getResourceableId());
+		for(Identity assessedUser:assessedUsers) {
+			if(!duplicateKiller.contains(assessedUser)) {
+				assessableIdentities.add(assessedUser);
+				duplicateKiller.add(assessedUser);
+			}
+		}
+
+		return assessableIdentities;
+	}
+	
+	private List<Identity> getAllIdentitiesWithCourseAssessmentData(Long resourceId) {
+		StringBuilder query = new StringBuilder();
+		query.append("select p.identity from ")
+			.append(Property.class.getName()).append(" as p")
+			.append(" where p.resourceTypeName = 'CourseModule'")
+			.append(" and p.resourceTypeId = :resid")
+			.append(" and p.identity is not null")
+			.append(" and p.name in ('").append(SCORE).append("','").append(PASSED).append("')");
+
+		return DBFactory.getInstance().getCurrentEntityManager()
+				.createQuery(query.toString(), Identity.class)
+				.setParameter("resid", resourceId)
+				.getResultList();
+	}
+	
+	private AssessmentEntryImpl createAssessmentEntry(Property property, RepositoryEntry courseEntry,
+			String nodeIdent, RepositoryEntry referenceEntry) {
+		AssessmentEntryImpl entry = new AssessmentEntryImpl();
+		entry.setCreationDate(property.getCreationDate());
+		entry.setLastModified(property.getLastModified());
+		entry.setIdentity(property.getIdentity());
+		entry.setRepositoryEntry(courseEntry);
+		entry.setSubIdent(nodeIdent);
+		entry.setReferenceEntry(referenceEntry);
+		return entry;
+	}
+
+	private void copyAssessmentProperty(Property property, AssessmentEntry nodeAssessment) {
+		String propertyName = property.getName();
+		if (propertyName.equals(ATTEMPTS)) {
+			if(property.getLongValue() != null) {
+				nodeAssessment.setAttempts(property.getLongValue().intValue());
+			}
+		} else if (propertyName.equals(SCORE)) {
+			if(property.getFloatValue() != null) {
+				BigDecimal score = new BigDecimal(Float.toString(property.getFloatValue().floatValue()));
+				nodeAssessment.setScore(score);
+			}	
+		} else if (propertyName.equals(PASSED)) {
+			if(StringHelper.containsNonWhitespace(property.getStringValue())) {
+				nodeAssessment.setPassed(new Boolean(property.getStringValue()));
+			}
+		} else if(propertyName.equals(FULLY_ASSESSED)) {
+			if(StringHelper.containsNonWhitespace(property.getStringValue())) {
+				nodeAssessment.setFullyAssessed(new Boolean(property.getStringValue()));
+			}
+		} else if (propertyName.equals(ASSESSMENT_ID)) {
+			nodeAssessment.setAssessmentId(property.getLongValue());
+		} else if (propertyName.equals(COMMENT)) {
+			nodeAssessment.setComment(property.getTextValue());
+		} else if(propertyName.equals(COACH_COMMENT)) {
+			nodeAssessment.setCoachComment(property.getTextValue());
+		}
+	}
+	
+	private List<AssessmentEntryImpl> loadAssessmentEntries(RepositoryEntry courseEntry) {
+		String sb = "select data from assessmententry data where data.repositoryEntry.key=:courseEntryKey";
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb, AssessmentEntryImpl.class)
+				.setParameter("courseEntryKey", courseEntry.getKey())
+				.getResultList();
+	}
+	
+	private List<Property> loadAssessmentProperties(RepositoryEntry course) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("from org.olat.properties.Property as p")
+		  .append(" inner join fetch p.identity as ident ")
+		  .append(" inner join fetch ident.user as user ")
+		  .append(" where p.resourceTypeId = :restypeid and p.resourceTypeName = :restypename")
+		  .append(" and p.name in ('")
+		  .append(ATTEMPTS).append("','")
+		  .append(SCORE).append("','")
+		  .append(FULLY_ASSESSED).append("','")
+		  .append(PASSED).append("','")
+		  .append(ASSESSMENT_ID).append("','")
+		  .append(COMMENT).append("','")
+		  .append(COACH_COMMENT)
+		  .append("')");
+
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Property.class)
+				.setParameter("restypename", course.getOlatResource().getResourceableTypeName())
+				.setParameter("restypeid", course.getOlatResource().getResourceableId())
+				.getResultList();	
+	}
+	
+	private static class AssessmentDataKey {
+		
+		private final Long courseId;
+		private final Long identityKey;
+		private final String courseNodeIdent;
+		
+		public AssessmentDataKey(Identity identity, Long courseOresId, String courseNodeIdent) {
+			this.courseId = courseOresId;
+			this.identityKey = identity.getKey();
+			this.courseNodeIdent = courseNodeIdent;
+		}
+		
+		public AssessmentDataKey(Long identityKey, Long courseOresId, String courseNodeIdent) {
+			this.courseId = courseOresId;
+			this.identityKey = identityKey;
+			this.courseNodeIdent = courseNodeIdent;
+		}
+		
+		public AssessmentDataKey(AssessmentEntry nodeAssessment) {
+			this.courseId = nodeAssessment.getRepositoryEntry().getOlatResource().getResourceableId();
+			this.identityKey = nodeAssessment.getIdentity().getKey();
+			this.courseNodeIdent = nodeAssessment.getSubIdent();
+		}
+
+		@Override
+		public int hashCode() {
+			return (courseId == null ? 32876 : courseId.hashCode())
+					+ (identityKey == null ? 7525 : identityKey.hashCode())
+					+ (courseNodeIdent == null ? 39841 : courseNodeIdent.hashCode());
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if(this == obj) {
+				return true;
+			}
+			if(obj instanceof AssessmentDataKey) {
+				AssessmentDataKey key = (AssessmentDataKey)obj;
+				return courseId != null && courseId.equals(key.courseId)
+						&& identityKey != null && identityKey.equals(key.identityKey)
+						&& courseNodeIdent != null && courseNodeIdent.equals(key.courseNodeIdent);	
+			}	
+			return false;
+		} 	
+	}
+	
+	private static class StaticCacheWrapper implements CacheWrapper<NewCacheKey,HashMap<String, Serializable>> {
+		
+		private ConcurrentHashMap<NewCacheKey,HashMap<String, Serializable>> map = new ConcurrentHashMap<>();
+
+		@Override
+		public boolean containsKey(NewCacheKey key) {
+			return map.containsKey(key);
+		}
+
+		@Override
+		public HashMap<String, Serializable> get(NewCacheKey key) {
+			return map.get(key);
+		}
+
+		@Override
+		public HashMap<String, Serializable> update(NewCacheKey key, HashMap<String, Serializable> value) {
+			return map.put(key, value);
+		}
+
+		@Override
+		public HashMap<String, Serializable> put(NewCacheKey key, HashMap<String, Serializable> value) {
+			return map.put(key, value);
+		}
+
+		@Override
+		public HashMap<String, Serializable> putIfAbsent(NewCacheKey key, HashMap<String, Serializable> value) {
+			return map.putIfAbsent(key, value);
+		}
+
+		@Override
+		public List<NewCacheKey> getKeys() {
+			return new ArrayList<>(map.keySet());
+		}
+
+		@Override
+		public HashMap<String, Serializable> remove(NewCacheKey key) {
+			return map.remove(key);
+		}
+
+		@Override
+		public int size() {
+			return map.size();
+		}
+
+		@Override
+		public Iterator<NewCacheKey> iterateKeys() {
+			return map.keySet().iterator();
+		}
+	}
+}
diff --git a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
index 52fdefa2e8b22db8991d2fd271d27cc97e964ca7..d216c12061a06da2c7e2a326e7708edd5a6337d7 100644
--- a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
+++ b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
@@ -44,6 +44,7 @@
 				<bean id="upgrade_10_0_3" class="org.olat.upgrade.OLATUpgrade_10_0_3"/>
 				<bean id="upgrade_10_1_0" class="org.olat.upgrade.OLATUpgrade_10_1_0"/>
 				<bean id="upgrade_10_3_0" class="org.olat.upgrade.OLATUpgrade_10_3_0"/>
+				<bean id="upgrade_11_0_0" class="org.olat.upgrade.OLATUpgrade_11_0_0"/>
 			</list>
 		</property>
 	</bean>
diff --git a/src/main/java/org/olat/course/assessment/NewCacheKey.java b/src/main/java/org/olat/upgrade/legacy/NewCacheKey.java
similarity index 98%
rename from src/main/java/org/olat/course/assessment/NewCacheKey.java
rename to src/main/java/org/olat/upgrade/legacy/NewCacheKey.java
index 30b8f2c33080fb6bc7776997a855107071302e11..cdaa56a697952d124f56c5cce4c0cef09da70504 100644
--- a/src/main/java/org/olat/course/assessment/NewCacheKey.java
+++ b/src/main/java/org/olat/upgrade/legacy/NewCacheKey.java
@@ -17,7 +17,7 @@
  * frentix GmbH, http://www.frentix.com
  * <p>
  */
-package org.olat.course.assessment;
+package org.olat.upgrade.legacy;
 
 import java.io.Serializable;
 
diff --git a/src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java b/src/main/java/org/olat/upgrade/legacy/NewCachePersistingAssessmentManager.java
similarity index 97%
rename from src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java
rename to src/main/java/org/olat/upgrade/legacy/NewCachePersistingAssessmentManager.java
index 89609755385339918ddfa3217ac4d20ae660e84d..472f747e5c1cc6b3e360689c25eb822b07e1baca 100644
--- a/src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java
+++ b/src/main/java/org/olat/upgrade/legacy/NewCachePersistingAssessmentManager.java
@@ -23,7 +23,7 @@
 * under the Apache 2.0 license as the original file.
 */
 
-package org.olat.course.assessment;
+package org.olat.upgrade.legacy;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -45,7 +45,6 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.logging.activity.StringResourceableType;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
-import org.olat.core.manager.BasicManager;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.cache.CacheWrapper;
 import org.olat.core.util.coordinate.CoordinatorManager;
@@ -56,6 +55,10 @@ import org.olat.core.util.mail.MailerResult;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
+import org.olat.course.assessment.AssessmentChangedEvent;
+import org.olat.course.assessment.AssessmentLoggingAction;
+import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.EfficiencyStatementManager;
 import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.certificate.CertificateTemplate;
 import org.olat.course.certificate.CertificatesManager;
@@ -106,9 +109,18 @@ import org.olat.util.logging.activity.LoggingResourceable;
  * 
  * @author Felix Jost
  */
-public class NewCachePersistingAssessmentManager extends BasicManager implements AssessmentManager {
+public class NewCachePersistingAssessmentManager {
 	
 	private static final OLog log = Tracing.createLoggerFor(NewCachePersistingAssessmentManager.class);
+	
+	public static final String SCORE = "SCORE";
+	public static final String PASSED = "PASSED";
+	public static final String ATTEMPTS = "ATTEMPTS";
+	public static final String COMMENT = "COMMENT";
+	public static final String COACH_COMMENT = "COACH_COMMENT";
+	public static final String ASSESSMENT_ID = "ASSESSMENT_ID";
+
+	public final static String FULLY_ASSESSED = "FULLY_ASSESSED";
 
 	/**
 	 * the key under which a hashmap is stored in a cachewrapper. we only use one key so that either all values of a user are there or none are there.
@@ -126,32 +138,21 @@ public class NewCachePersistingAssessmentManager extends BasicManager implements
 	private CacheWrapper<NewCacheKey,HashMap<String, Serializable>> courseCache;
 	private OLATResourceable ores;
 
-	
-	// we cannot store the ref to cpm here, since at the time where the assessmentManager is initialized, the given course is not fully initialized yet.
-	//does not work: final CoursePropertyManager cpm; 
-		
-	/**
-	 * Get an instance of the persisting assessment manager. This will use the
-	 * course property manager to persist assessment data. THIS METHOD MUST ONLY
-	 * BE USED WITHIN THE COURSE CONSTRUCTOR. Use course.getAssessmentManager() to
-	 * use the assessment manager during runtime!
-	 * 
-	 * @param course
-	 * @return The assessment manager for this course
-	 */
-	public static AssessmentManager getInstance(ICourse course) {
-		return new NewCachePersistingAssessmentManager(course);
-	}
-
 	/**
 	 * Private since singleton
 	 */
-	private NewCachePersistingAssessmentManager(ICourse course) {
+	public NewCachePersistingAssessmentManager(ICourse course) {
 		this.ores = course;
 		//String cacheName = "Course@" + course.getResourceableId();
 		courseCache = CoordinatorManager.getInstance().getCoordinator().getCacher()
 				.getCache(AssessmentManager.class.getSimpleName(), "newpersisting");
 	}
+	
+	public NewCachePersistingAssessmentManager(ICourse course, CacheWrapper<NewCacheKey,HashMap<String, Serializable>> cache) {
+		this.ores = course;
+		//String cacheName = "Course@" + course.getResourceableId();
+		courseCache = cache;
+	}
 	/**
 	 * @param identity the identity for which to properties are to be loaded. 
 	 * if null, the properties of all identities (=all properties of this course)
@@ -191,13 +192,11 @@ public class NewCachePersistingAssessmentManager extends BasicManager implements
 	/**
 	 * @see org.olat.course.assessment.AssessmentManager#preloadCache(org.olat.core.id.Identity)
 	 */
-	@Override
 	public void preloadCache(Identity identity) {
 		// triggers loading of data of the given user.
 		getOrLoadScorePassedAttemptsMap(identity, null, false);
 	}
 
-	@Override
 	public void preloadCache(List<Identity> identities) {
 		int count = 0;
 		int batch = 200;
@@ -573,7 +572,6 @@ public class NewCachePersistingAssessmentManager extends BasicManager implements
 	 * @see org.olat.course.assessment.AssessmentManager#incrementNodeAttemptsInBackground(org.olat.course.nodes.CourseNode,
 	 *      org.olat.core.id.Identity, org.olat.course.run.userview.UserCourseEnvironment)
 	 */
-	@Override
 	public void incrementNodeAttemptsInBackground(CourseNode courseNode, Identity identity, UserCourseEnvironment userCourseEnv) {
 		incrementNodeAttempts(courseNode, identity, userCourseEnv, false);
 	}
@@ -720,7 +718,6 @@ public class NewCachePersistingAssessmentManager extends BasicManager implements
 		}		
 	}
 
-	@Override
 	public Boolean getNodeFullyAssessed(CourseNode courseNode, Identity identity) {
 		Boolean fullyAssessed = null;
 		if (courseNode != null) {
@@ -835,7 +832,6 @@ public class NewCachePersistingAssessmentManager extends BasicManager implements
 		}				
 	}
 	
-	@Override
 	public Date getScoreLastModifiedDate(CourseNode courseNode, Identity identity) {
 		if (courseNode == null) {
 			return null; // return default value
diff --git a/src/main/java/org/olat/user/UserManager.java b/src/main/java/org/olat/user/UserManager.java
index 9aa14e10455301b54831307fb7afcb7fcf9fcf9e..b198f11d88e89820ce0f6b0a75b43b1b999578bb 100644
--- a/src/main/java/org/olat/user/UserManager.java
+++ b/src/main/java/org/olat/user/UserManager.java
@@ -30,6 +30,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.olat.basesecurity.IdentityNames;
+import org.olat.basesecurity.IdentityRef;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.User;
@@ -262,6 +263,8 @@ public abstract class UserManager extends BasicManager {
 	 */
 	public abstract String getUserDisplayName(Identity identity);
 	
+	public abstract String getUserDisplayName(IdentityRef identity);
+	
 	/**
 	 * 
 	 * @param identityKeys
diff --git a/src/main/java/org/olat/user/UserManagerImpl.java b/src/main/java/org/olat/user/UserManagerImpl.java
index b29af80ff6a91656397eed8c5c91e8d81c75f322..8b0847beb9e827e897851b12f2159d1cce2877c8 100644
--- a/src/main/java/org/olat/user/UserManagerImpl.java
+++ b/src/main/java/org/olat/user/UserManagerImpl.java
@@ -36,6 +36,7 @@ import javax.persistence.TypedQuery;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.IdentityImpl;
 import org.olat.basesecurity.IdentityNames;
+import org.olat.basesecurity.IdentityRef;
 import org.olat.basesecurity.IdentityShort;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.DBFactory;
@@ -534,6 +535,14 @@ public class UserManagerImpl extends UserManager {
 		return fullNames;
 	}
 
+	@Override
+	public String getUserDisplayName(IdentityRef identity) {
+		if(identity instanceof Identity) {
+			return getUserDisplayName((Identity)identity);
+		}
+		return getUserDisplayName(identity.getKey());
+	}
+
 	@Override
 	public String getUserDisplayName(Identity identity) {
 		if (userDisplayNameCreator == null || identity == null) return "";
diff --git a/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql b/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql
index ba04f9ce30e30836d1108475cd15a49f1619ce88..e4b4f1bbab4225a718388d92f789f33faa7f4e00 100644
--- a/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql
+++ b/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql
@@ -20,3 +20,30 @@ alter table o_qti_assessment_session add constraint qti_sess_to_course_entry_idx
 alter table o_qti_assessment_session add constraint qti_sess_to_identity_idx foreign key (fk_identity) references o_bs_identity (id);
 
 
+
+create table o_as_entry (
+   id bigint not null auto_increment,
+   creationdate datetime not null,
+   lastmodified datetime not null,
+   a_attemtps bigint default null,
+   a_score float(65,30) default null,
+   a_passed bit default null, 
+   a_fully_assessed bit default null,
+   a_assessment_id bigint default null,
+   a_completion float(65,30),
+   a_comment text,
+   a_coach_comment text,
+   fk_entry bigint not null,
+   a_subident varchar(64),
+   fk_reference_entry bigint not null,
+   fk_identity bigint not null,
+   primary key (id),
+   unique (fk_identity, fk_entry, a_subident)
+);
+alter table o_as_entry ENGINE = InnoDB;
+
+alter table o_as_entry add constraint as_entry_to_identity_idx foreign key (fk_identity) references o_bs_identity (id);
+alter table o_as_entry add constraint as_entry_to_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id);
+alter table o_as_entry add constraint as_entry_to_refentry_idx foreign key (fk_reference_entry) references o_repositoryentry (repositoryentry_id);
+
+create index idx_as_entry_to_id_idx on o_as_entry (a_assessment_id);
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index d3bcd0b99c1f345c4603a65c844a2cd231c1ca6b..1988ee14ff9c289254731249acc37ca49a22d864 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1064,6 +1064,26 @@ create table o_as_user_course_infos (
    primary key (id)
 );
 
+create table o_as_entry (
+   id bigint not null auto_increment,
+   creationdate datetime not null,
+   lastmodified datetime not null,
+   a_attemtps bigint default null,
+   a_score float(65,30) default null,
+   a_passed bit default null, 
+   a_fully_assessed bit default null,
+   a_assessment_id bigint default null,
+   a_completion float(65,30),
+   a_comment text,
+   a_coach_comment text,
+   fk_entry bigint not null,
+   a_subident varchar(64),
+   fk_reference_entry bigint not null,
+   fk_identity bigint not null,
+   primary key (id),
+   unique (fk_identity, fk_entry, a_subident)
+);
+
 create table o_as_mode_course (
    id bigint not null,
    creationdate datetime not null,
@@ -1750,7 +1770,7 @@ alter table o_ac_paypal_transaction ENGINE = InnoDB;
 alter table o_as_eff_statement ENGINE = InnoDB;
 alter table o_as_user_course_infos ENGINE = InnoDB;
 alter table o_as_mode_course ENGINE = InnoDB;
-alter table o_as_mode_course ENGINE = InnoDB;
+alter table o_as_entry ENGINE = InnoDB;
 alter table o_as_mode_course_to_area ENGINE = InnoDB;
 alter table o_mapper ENGINE = InnoDB;
 alter table o_qti_assessment_session ENGINE = InnoDB;
@@ -2074,6 +2094,12 @@ alter table o_as_user_course_infos add index user_course_infos_id_cstr (fk_ident
 alter table o_as_user_course_infos add index user_course_infos_res_cstr (fk_resource_id), add constraint user_course_infos_res_cstr foreign key (fk_resource_id) references o_olatresource (resource_id);
 alter table o_as_user_course_infos add unique (fk_identity, fk_resource_id);
 
+alter table o_as_entry add constraint as_entry_to_identity_idx foreign key (fk_identity) references o_bs_identity (id);
+alter table o_as_entry add constraint as_entry_to_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id);
+alter table o_as_entry add constraint as_entry_to_refentry_idx foreign key (fk_reference_entry) references o_repositoryentry (repositoryentry_id);
+
+create index idx_as_entry_to_id_idx on o_as_entry (a_assessment_id);
+
 -- mapper
 create index o_mapper_uuid_idx on o_mapper (mapper_uuid);
 
diff --git a/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql b/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql
index acf7795ad120bfd94a9a913266f16b2e3ee25523..ec896e6017d9be197ece2df257a91ad29eba1bda 100644
--- a/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql
+++ b/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql
@@ -19,4 +19,37 @@ create index idx_testess_to_repo_entry_idx on o_qti_assessment_session (fk_entry
 alter table o_qti_assessment_session add constraint qti_sess_to_course_entry_idx foreign key (fk_course) references o_repositoryentry (repositoryentry_id);
 create index idx_qti_sess_to_course_entry_idx on o_qti_assessment_session (fk_course);
 alter table o_qti_assessment_session add constraint qti_sess_to_identity_idx foreign key (fk_identity) references o_bs_identity (id);
-create index idx_qti_sess_to_identity_idx on o_qti_assessment_session (fk_identity);
\ No newline at end of file
+create index idx_qti_sess_to_identity_idx on o_qti_assessment_session (fk_identity);
+
+
+
+create table o_as_entry (
+   id bigserial,
+   creationdate timestamp not null,
+   lastmodified timestamp not null,
+   a_attemtps int8 default null,
+   a_score decimal default null,
+   a_passed bool default null,
+   a_fully_assessed bool default null,
+   a_assessment_id int8 default null,
+   a_completion float(24),
+   a_comment text,
+   a_coach_comment text,
+   fk_entry int8 not null,
+   a_subident varchar(64),
+   fk_reference_entry int8 not null,
+   fk_identity int8 not null,
+   primary key (id),
+   unique(fk_identity, fk_entry, a_subident)
+);
+
+alter table o_as_entry add constraint as_entry_to_identity_idx foreign key (fk_identity) references o_bs_identity (id);
+create index idx_as_entry_to_ident_idx on o_as_entry (fk_identity);
+alter table o_as_entry add constraint as_entry_to_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id);
+create index idx_as_entry_to_entry_idx on o_as_entry (fk_entry);
+alter table o_as_entry add constraint as_entry_to_refentry_idx foreign key (fk_reference_entry) references o_repositoryentry (repositoryentry_id);
+create index idx_as_entry_to_refentry_idx on o_as_entry (fk_reference_entry);
+
+create index idx_as_entry_to_id_idx on o_as_entry (a_assessment_id);
+
+
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index d0567fc794d6524817a11818f9a9386c83d93513..3cbe71a6ab2acb59f679422d96a303742ab75473 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1065,6 +1065,26 @@ create table o_as_user_course_infos (
    primary key (id)
 );
 
+create table o_as_entry (
+   id bigserial,
+   creationdate timestamp not null,
+   lastmodified timestamp not null,
+   a_attemtps int8 default null,
+   a_score decimal default null,
+   a_passed bool default null,
+   a_fully_assessed bool default null,
+   a_assessment_id int8 default null,
+   a_completion float(24),
+   a_comment text,
+   a_coach_comment text,
+   fk_entry int8 not null,
+   a_subident varchar(64),
+   fk_reference_entry int8 not null,
+   fk_identity int8 not null,
+   primary key (id),
+   unique(fk_identity, fk_entry, a_subident)
+);
+
 create table o_as_mode_course (
    id int8 not null,
    creationdate timestamp not null,
@@ -2073,6 +2093,15 @@ alter table o_as_user_course_infos add constraint user_course_infos_res_cstr for
 create index idx_ucourseinfos_rsrc_idx on o_as_user_course_infos (fk_resource_id);
 alter table o_as_user_course_infos add unique (fk_identity, fk_resource_id);
 
+alter table o_as_entry add constraint as_entry_to_identity_idx foreign key (fk_identity) references o_bs_identity (id);
+create index idx_as_entry_to_ident_idx on o_as_entry (fk_identity);
+alter table o_as_entry add constraint as_entry_to_entry_idx foreign key (fk_entry) references o_repositoryentry (repositoryentry_id);
+create index idx_as_entry_to_entry_idx on o_as_entry (fk_entry);
+alter table o_as_entry add constraint as_entry_to_refentry_idx foreign key (fk_reference_entry) references o_repositoryentry (repositoryentry_id);
+create index idx_as_entry_to_refentry_idx on o_as_entry (fk_reference_entry);
+
+create index idx_as_entry_to_id_idx on o_as_entry (a_assessment_id);
+
 -- mapper
 create index o_mapper_uuid_idx on o_mapper (mapper_uuid);
 
diff --git a/src/test/java/org/olat/modules/assessment/manager/AssessmentEntryDAOTest.java b/src/test/java/org/olat/modules/assessment/manager/AssessmentEntryDAOTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e0a33470d3cda87aee04beefda625873b695eb2
--- /dev/null
+++ b/src/test/java/org/olat/modules/assessment/manager/AssessmentEntryDAOTest.java
@@ -0,0 +1,104 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.assessment.manager;
+
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.modules.assessment.AssessmentEntry;
+import org.olat.modules.assessment.manager.AssessmentEntryDAO;
+import org.olat.repository.RepositoryEntry;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
+
+
+/**
+ * 
+ * Initial date: 20.07.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class AssessmentEntryDAOTest extends OlatTestCase {
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private AssessmentEntryDAO courseNodeAssessmentDao;
+	
+	@Test
+	public void createCourseNodeAssessment() {
+		Identity assessedIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("as-node-1");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		String courseNodeIdent = "39485349759";
+
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.createCourseNodeAssessment(assessedIdentity, entry, courseNodeIdent, entry);
+		Assert.assertNotNull(nodeAssessment);
+		dbInstance.commitAndCloseSession();
+		
+		//check values
+		Assert.assertNotNull(nodeAssessment.getKey());
+		Assert.assertNotNull(nodeAssessment.getCreationDate());
+		Assert.assertNotNull(nodeAssessment.getLastModified());
+		Assert.assertEquals(assessedIdentity, nodeAssessment.getIdentity());
+		Assert.assertEquals(entry, nodeAssessment.getRepositoryEntry());
+		Assert.assertEquals(courseNodeIdent, nodeAssessment.getSubIdent());
+	}
+	
+	@Test
+	public void loadCourseNodeAssessmentById() {
+		Identity assessedIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("as-node-2");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		String courseNodeIdent = UUID.randomUUID().toString();
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.createCourseNodeAssessment(assessedIdentity, entry, courseNodeIdent, entry);
+		dbInstance.commitAndCloseSession();
+		
+		AssessmentEntry reloadedAssessment = courseNodeAssessmentDao.loadAssessmentEntryById(nodeAssessment.getKey());
+		Assert.assertEquals(nodeAssessment.getKey(), reloadedAssessment.getKey());
+		Assert.assertEquals(nodeAssessment, reloadedAssessment);
+		Assert.assertEquals(assessedIdentity, reloadedAssessment.getIdentity());
+		Assert.assertEquals(entry, reloadedAssessment.getRepositoryEntry());
+		Assert.assertEquals(courseNodeIdent, reloadedAssessment.getSubIdent());
+	}
+	
+	@Test
+	public void loadCourseNodeAssessment() {
+		Identity assessedIdentity = JunitTestHelper.createAndPersistIdentityAsRndUser("as-node-3");
+		RepositoryEntry entry = JunitTestHelper.createAndPersistRepositoryEntry();
+		String courseNodeIdent = UUID.randomUUID().toString();
+		AssessmentEntry nodeAssessment = courseNodeAssessmentDao
+				.createCourseNodeAssessment(assessedIdentity, entry, courseNodeIdent, entry);
+		dbInstance.commitAndCloseSession();
+		
+		AssessmentEntry reloadedAssessment = courseNodeAssessmentDao
+				.loadAssessmentEntry(assessedIdentity, entry, courseNodeIdent);
+		Assert.assertEquals(nodeAssessment.getKey(), reloadedAssessment.getKey());
+		Assert.assertEquals(nodeAssessment, reloadedAssessment);
+		Assert.assertEquals(assessedIdentity, reloadedAssessment.getIdentity());
+		Assert.assertEquals(entry, reloadedAssessment.getRepositoryEntry());
+		Assert.assertEquals(courseNodeIdent, reloadedAssessment.getSubIdent());
+	}
+
+}
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index d4e5cb2ec82550665513f44d017e699b2349c036..985fcbc9d53c839cfb94a640d2267302ae71890a 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -129,6 +129,7 @@ import org.junit.runners.Suite;
 	org.olat.course.assessment.AssessmentManagerTest.class,
 	org.olat.course.assessment.manager.UserCourseInformationsManagerTest.class,
 	org.olat.course.assessment.manager.AssessmentModeManagerTest.class,
+	org.olat.modules.assessment.manager.AssessmentEntryDAOTest.class,
 	org.olat.course.certificate.manager.CertificatesManagerTest.class,
 	org.olat.course.config.CourseConfigManagerImplTest.class,
 	org.olat.course.groupsandrights.CourseGroupManagementTest.class,