diff --git a/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java b/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java
index 1a2f4419483ca9f10835ff175d97b985d9421209..69f5eb36d655b44bfbd045086261ba701f266a1d 100644
--- a/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java
+++ b/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java
@@ -61,6 +61,7 @@ import org.olat.core.util.openxml.OpenXMLWorksheet.Row;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
 import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.manager.UserCourseInformationsManager;
 import org.olat.course.groupsandrights.CourseGroupManager;
@@ -134,6 +135,7 @@ public class ScoreAccountingHelper {
 	 * @param bos The output stream (which will be closed at the end, if you use a zip stream don't forget to shield it).
 	 */
 	public static void createCourseResultsOverviewXMLTable(List<Identity> identities, List<AssessableCourseNode> myNodes, ICourse course, Locale locale, OutputStream bos) {
+		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 		OpenXMLWorkbook workbook = new OpenXMLWorkbook(bos, 1);
 		OpenXMLWorksheet sheet = workbook.nextWorksheet();
 		sheet.setHeaderRows(2);
@@ -269,7 +271,7 @@ public class ScoreAccountingHelper {
 				boolean commentOk = assessmentConfig.hasComment();
 
 				if (acnode.getType().equals("ita")) {
-					String log = acnode.getUserLog(uce);
+					String log = courseAssessmentService.getUserLog(acnode, uce);
 					String date = null;
 					Date lastUploaded = null;
 					try {
diff --git a/src/main/java/org/olat/course/assessment/AssessmentHelper.java b/src/main/java/org/olat/course/assessment/AssessmentHelper.java
index 334ec60fe42ad0a82f1256ce0db4e100c79f28b9..2b5a4f40d92773bdfd9dcfac36adc0fdaff380be 100644
--- a/src/main/java/org/olat/course/assessment/AssessmentHelper.java
+++ b/src/main/java/org/olat/course/assessment/AssessmentHelper.java
@@ -36,6 +36,7 @@ import java.util.Locale;
 import java.util.Map;
 
 import org.apache.logging.log4j.Logger;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.components.tree.GenericTreeModel;
 import org.olat.core.gui.components.tree.GenericTreeNode;
 import org.olat.core.gui.components.tree.TreeModel;
@@ -153,13 +154,14 @@ public class AssessmentHelper {
 	 * @return a wrapped identity
 	 */
 	public static AssessedIdentityWrapper wrapIdentity(UserCourseEnvironment uce, Date initialLaunchDate, AssessableCourseNode courseNode) {
+		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 		// Fetch attempts and details for this node if available
 		Integer attempts = null;
 		String details = null;
 		if (courseNode != null) {
 			AssessmentConfig assessmentConfig = courseNode.getAssessmentConfig();
 			if (assessmentConfig.hasAttempts()) {
-				attempts = courseNode.getUserAttempts(uce);
+				attempts = courseAssessmentService.getUserAttempts(courseNode, uce);
 			}
 			if (courseNode.hasDetails()) {
 				details = courseNode.getDetailsListView(uce);
@@ -572,7 +574,8 @@ public class AssessmentHelper {
 				  // comments are invisible in the table but if configured the node must be in the list
 					// for the efficiency statement this can be ignored, this is the case when discardComments is true
 					hasDisplayableValuesConfigured = true;
-					if (assessableCourseNode.getUserComment(userCourseEnv) != null) {
+					CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+					if (courseAssessmentService.getUserComment(assessableCourseNode, userCourseEnv) != null) {
 						hasDisplayableUserValues = true;
 					}
 				}
diff --git a/src/main/java/org/olat/course/assessment/CourseAssessmentService.java b/src/main/java/org/olat/course/assessment/CourseAssessmentService.java
new file mode 100644
index 0000000000000000000000000000000000000000..42263eb90b5542892eecb9241e931fa310ad8d3b
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/CourseAssessmentService.java
@@ -0,0 +1,170 @@
+/**
+ * <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.io.File;
+import java.util.List;
+
+import org.olat.core.id.Identity;
+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.Role;
+import org.olat.modules.assessment.model.AssessmentRunStatus;
+
+/**
+ * 
+ * Initial date: 20 Aug 2019<br>
+ * 
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public interface CourseAssessmentService {
+
+	public void updateUserScoreEvaluation(CourseNode courseNode, ScoreEvaluation scoreEvaluation,
+			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, boolean incrementAttempts, Role by);
+
+	/**
+	 * 
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return The completion of its current task before being committed and
+	 *         official.
+	 */
+	public Double getUserCurrentRunCompletion(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
+
+	public void updateCurrentCompletion(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment,
+			Identity identity, Double currentCompletion, AssessmentRunStatus status, Role by);
+
+	/**
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return the users attempts of the node
+	 */
+	public Integer getUserAttempts(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
+
+	/**
+	 * Increments the users attempts for this node and this user.
+	 * 
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @param doneBy
+	 */
+	public void incrementUserAttempts(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment, Role doneBy);
+
+	/**
+	 * Updates the users attempts for this node and this user.
+	 * 
+	 * @param courseNode
+	 * @param userAttempts
+	 * @param userCourseEnvironment
+	 * @param coachingIdentity
+	 * @param doneBy
+	 */
+	public void updateUserAttempts(CourseNode courseNode, Integer userAttempts,
+			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role doneBy);
+	
+	/**
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return the user comment for this user for this node, given by coach
+	 */
+	public String getUserComment(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
+
+	/**
+	 * Updates the user comment for this node and this user. This comment is visible
+	 * to the user.
+	 * 
+	 * @param courseNode
+	 * @param userComment
+	 * @param userCourseEnvironment
+	 * @param coachingIdentity
+	 */
+	public void updatedUserComment(CourseNode courseNode, String userComment,
+			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity);
+
+	/**
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return The coach comment for this user for this node (not visible to user)
+	 */
+	public String getCoachComment(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
+
+	/**
+	 * Updates the coach comment for this node and this user. This comment is not
+	 * visible to the user.
+	 * 
+	 * @param courseNode
+	 * @param coachComment
+	 * @param userCourseEnvironment
+	 */
+	public void updateCoachComment(CourseNode courseNode, String coachComment,
+			UserCourseEnvironment userCourseEnvironment);
+
+	/**
+	 * @param courseNode
+	 * @param userCourseEnvironment The course environment of the assessed user.
+	 * @return The list of assessment document associated with this user and course
+	 *         element.
+	 */
+	public List<File> getIndividualAssessmentDocuments(CourseNode courseNode,
+			UserCourseEnvironment userCourseEnvironment);
+
+	/**
+	 * Add a document for the assessed user, if allowed.
+	 * 
+	 * @param courseNode
+	 * @param document              The document
+	 * @param userCourseEnvironment The course environment of the assessed user
+	 * @param coachingIdentity      The coach who upload the document
+	 */
+	public void addIndividualAssessmentDocument(CourseNode courseNode, File document, String filename,
+			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity);
+
+	/**
+	 * Remove a document.
+	 * 
+	 * @param courseNode
+	 * @param document              The document to remove
+	 * @param userCourseEnvironment The course environment of the assessed user
+	 * @param coachingIdentity      The coach who delete the document
+	 */
+	public void removeIndividualAssessmentDocument(CourseNode courseNode, File document,
+			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity);
+	
+	/**
+	 * 
+	 * @param courseNode
+	 * @param userCourseEnvironment The user course environment of the assessed
+	 *                              identity
+	 * @param identity              The identity which do the action
+	 * @param doneBy                The role of the identity which do the action
+	 */
+	public void updateLastModifications(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment,
+			Identity identity, Role doneBy);
+
+	/**
+	 * @param courseNode
+	 * @param userCourseEnvironment
+	 * @return the users log of this node
+	 */
+	public String getUserLog(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
+
+}
diff --git a/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java b/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java
index 64c2965479492d6ccfe69cddf8292ccc68ab5330..08c5ee47036c692b705dd13af7a0b810e37ed28f 100644
--- a/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java
+++ b/src/main/java/org/olat/course/assessment/manager/BulkAssessmentTask.java
@@ -72,6 +72,7 @@ import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
 import org.olat.course.assessment.AssessmentLoggingAction;
 import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.bulk.BulkAssessmentOverviewController;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.model.BulkAssessmentDatas;
@@ -308,6 +309,7 @@ public class BulkAssessmentTask implements LongRunnable, TaskAwareRunnable, Sequ
 	private void doProcess(List<BulkAssessmentFeedback> feedbacks) {
 		final DB dbInstance = DBFactory.getInstance();
 		final BaseSecurity securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
+		final CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 		final Identity coachIdentity = securityManager.loadIdentityByKey(coachedIdentity);
 		final ICourse course = CourseFactory.loadCourse(courseRes);
 		final AssessableCourseNode courseNode = getCourseNode();
@@ -358,8 +360,7 @@ public class BulkAssessmentTask implements LongRunnable, TaskAwareRunnable, Sequ
 			//update comment, empty string will reset comment
 			String userComment = row.getComment();
 			if(hasUserComment && userComment != null){
-				// Update userComment in db
-				courseNode.updatedUserComment(userComment, uce, coachIdentity);
+				courseAssessmentService.updatedUserComment(courseNode, userComment, uce, coachIdentity);
 				//LD: why do we have to update the efficiency statement?
 				//EfficiencyStatementManager esm =	EfficiencyStatementManager.getInstance();
 				//esm.updateUserEfficiencyStatement(uce);
@@ -389,7 +390,7 @@ public class BulkAssessmentTask implements LongRunnable, TaskAwareRunnable, Sequ
 					}
 					
 					// Update score,passed properties in db, and the user's efficiency statement
-					courseNode.updateUserScoreEvaluation(se, uce, coachIdentity, false, Role.auto);
+					courseAssessmentService.updateUserScoreEvaluation(courseNode, se, uce, coachIdentity, false, Role.auto);
 					statusVisibilitySet = true;
 				}
 			}
@@ -401,7 +402,7 @@ public class BulkAssessmentTask implements LongRunnable, TaskAwareRunnable, Sequ
 				ScoreEvaluation se = new ScoreEvaluation(oldScore, passed, datas.getStatus(), datas.getVisibility(), null, null, null, null);
 				// Update score,passed properties in db, and the user's efficiency statement
 				boolean incrementAttempts = false;
-				courseNode.updateUserScoreEvaluation(se, uce, coachIdentity, incrementAttempts, Role.auto);
+				courseAssessmentService.updateUserScoreEvaluation(courseNode, se, uce, coachIdentity, incrementAttempts, Role.auto);
 				statusVisibilitySet = true;
 			}
 			
@@ -436,7 +437,7 @@ public class BulkAssessmentTask implements LongRunnable, TaskAwareRunnable, Sequ
 						seOld.getCurrentRunCompletion(), seOld.getCurrentRunStatus(), seOld.getAssessmentID());
 				// Update score,passed properties in db, and the user's efficiency statement
 				boolean incrementAttempts = false;
-				courseNode.updateUserScoreEvaluation(se, uce, coachIdentity, incrementAttempts, Role.auto);
+				courseAssessmentService.updateUserScoreEvaluation(courseNode, se, uce, coachIdentity, incrementAttempts, Role.auto);
 			}
 			
 			if(count++ % 5 == 0) {
diff --git a/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java b/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..596517edb15a6c8818c0150adbb654fd0f709de2
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/manager/CourseAssessmentServiceImpl.java
@@ -0,0 +1,170 @@
+/**
+ * <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.io.File;
+import java.util.List;
+
+import org.olat.core.id.Identity;
+import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.CourseAssessmentService;
+import org.olat.course.auditing.UserNodeAuditManager;
+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.Role;
+import org.olat.modules.assessment.model.AssessmentRunStatus;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 20 Aug 2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class CourseAssessmentServiceImpl implements CourseAssessmentService {
+
+	@Override
+	public void updateUserScoreEvaluation(CourseNode courseNode, ScoreEvaluation scoreEvaluation,
+			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, boolean incrementAttempts, Role by) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		am.saveScoreEvaluation(courseNode, coachingIdentity, assessedIdentity, new ScoreEvaluation(scoreEvaluation),
+				userCourseEnvironment, incrementAttempts, by);
+	}
+
+	@Override
+	public Double getUserCurrentRunCompletion(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getNodeCurrentRunCompletion(courseNode, assessedIdentity);
+	}
+	
+	@Override
+	public void updateCurrentCompletion(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment,
+			Identity identity, Double currentCompletion, AssessmentRunStatus runStatus, Role by) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		am.updateCurrentCompletion(courseNode, assessedIdentity, userCourseEnvironment, currentCompletion, runStatus,
+				by);
+	}
+
+	@Override
+	public Integer getUserAttempts(CourseNode courseNode, UserCourseEnvironment userCourseEnv) {
+		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnv.getIdentityEnvironment().getIdentity();
+		return am.getNodeAttempts(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public void incrementUserAttempts(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment, Role by) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		am.incrementNodeAttempts(courseNode, assessedIdentity, userCourseEnvironment, by);
+	}
+
+	@Override
+	public void updateUserAttempts(CourseNode courseNode, Integer userAttempts,
+			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) {
+		if (userAttempts != null) {
+			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+			am.saveNodeAttempts(courseNode, coachingIdentity, assessedIdentity, userAttempts, by);
+		}
+	}
+
+	@Override
+	public String getUserComment(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getNodeComment(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public void updatedUserComment(CourseNode courseNode, String userComment,
+			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) {
+		if (userComment != null) {
+			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+			am.saveNodeComment(courseNode, coachingIdentity, assessedIdentity, userComment);
+		}
+	}
+
+	@Override
+	public String getCoachComment(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getNodeCoachComment(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public void updateCoachComment(CourseNode courseNode, String coachComment,
+			UserCourseEnvironment userCourseEnvironment) {
+		if (coachComment != null) {
+			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+			am.saveNodeCoachComment(courseNode, assessedIdentity, coachComment);
+		}
+	}
+	
+	@Override
+	public List<File> getIndividualAssessmentDocuments(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getIndividualAssessmentDocuments(courseNode, assessedIdentity);
+	}
+
+	@Override
+	public void addIndividualAssessmentDocument(CourseNode courseNode, File document, String filename,
+			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) {
+		if (document != null) {
+			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+			am.addIndividualAssessmentDocument(courseNode, coachingIdentity, assessedIdentity, document, filename);
+		}
+	}
+
+	@Override
+	public void removeIndividualAssessmentDocument(CourseNode courseNode, File document,
+			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) {
+		if (document != null) {
+			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+			am.removeIndividualAssessmentDocument(courseNode, coachingIdentity, assessedIdentity, document);
+		}
+	}
+
+	@Override
+	public void updateLastModifications(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment,
+			Identity identity, Role by) {
+		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		am.updateLastModifications(courseNode, assessedIdentity, userCourseEnvironment, by);
+	}
+
+	@Override
+	public String getUserLog(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
+		UserNodeAuditManager am = userCourseEnvironment.getCourseEnvironment().getAuditManager();
+		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
+		return am.getUserNodeLog(courseNode, assessedIdentity);
+	}
+
+}
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java
index 9ca662421f984a4fb94f91c6f656efb7f5aa3dc3..41f4a5faf1904f7300203e1b40c8c1029ba2ebc2 100644
--- a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java
+++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentForm.java
@@ -59,6 +59,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.course.assessment.AssessmentHelper;
 import org.olat.course.assessment.AssessmentModule;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.run.scoring.ScoreAccounting;
@@ -67,6 +68,7 @@ import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.modules.assessment.Role;
 import org.olat.modules.assessment.model.AssessmentEntryStatus;
 import org.olat.modules.assessment.ui.event.AssessmentFormEvent;
+import org.springframework.beans.factory.annotation.Autowired;
 
 
 /**
@@ -108,6 +110,10 @@ public class AssessmentForm extends FormBasicController {
 	private Float scoreValue;
 	private String userCommentValue, coachCommentValue;
 	
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+
+	
 	/**
 	 * Constructor for an assessment detail form. The form will be configured according
 	 * to the assessable course node parameters
@@ -239,8 +245,9 @@ public class AssessmentForm extends FormBasicController {
 			fireEvent(ureq, new AssessmentFormEvent(AssessmentFormEvent.ASSESSMENT_REOPEN, false));
 		} else if(uploadDocsEl == source) {
 			if(uploadDocsEl.getUploadFile() != null && StringHelper.containsNonWhitespace(uploadDocsEl.getUploadFileName())) {
-				assessableCourseNode.addIndividualAssessmentDocument(uploadDocsEl.getUploadFile(), uploadDocsEl.getUploadFileName(),
-						assessedUserCourseEnv, getIdentity());
+				courseAssessmentService.addIndividualAssessmentDocument(assessableCourseNode,
+						uploadDocsEl.getUploadFile(), uploadDocsEl.getUploadFileName(), assessedUserCourseEnv,
+						getIdentity());
 				reloadAssessmentDocs();
 				uploadDocsEl.reset();
 			}
@@ -329,7 +336,8 @@ public class AssessmentForm extends FormBasicController {
 			ScoreEvaluation reopenedEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(),
 					AssessmentEntryStatus.inReview, scoreEval.getUserVisible(), scoreEval.getFullyAssessed(),
 					scoreEval.getCurrentRunCompletion(), scoreEval.getCurrentRunStatus(), scoreEval.getAssessmentID());
-			assessableCourseNode.updateUserScoreEvaluation(reopenedEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+			courseAssessmentService.updateUserScoreEvaluation(assessableCourseNode, reopenedEval, assessedUserCourseEnv,
+					getIdentity(), false, Role.coach);
 			updateStatus(reopenedEval);
 		}
 	}
@@ -343,7 +351,8 @@ public class AssessmentForm extends FormBasicController {
 	}
 	
 	private void doDeleteAssessmentDocument(File document) {
-		assessableCourseNode.removeIndividualAssessmentDocument(document, assessedUserCourseEnv, getIdentity());
+		courseAssessmentService.removeIndividualAssessmentDocument(assessableCourseNode, document,
+				assessedUserCourseEnv, getIdentity());
 	}
 	
 	protected void doUpdateAssessmentData(boolean setAsDone) {
@@ -351,7 +360,8 @@ public class AssessmentForm extends FormBasicController {
 		Boolean updatedPassed = null;
 
 		if (isHasAttempts() && isAttemptsDirty()) {
-			assessableCourseNode.updateUserAttempts(new Integer(getAttempts()), assessedUserCourseEnv, getIdentity(), Role.coach);
+			courseAssessmentService.updateUserAttempts(assessableCourseNode, new Integer(getAttempts()),
+					assessedUserCourseEnv, getIdentity(), Role.coach);
 		}
 
 		if (isHasScore()) {
@@ -382,18 +392,17 @@ public class AssessmentForm extends FormBasicController {
 		} else {
 			scoreEval = new ScoreEvaluation(updatedScore, updatedPassed, null, visibility, null, null, null, null);
 		}
-		assessableCourseNode.updateUserScoreEvaluation(scoreEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+		courseAssessmentService.updateUserScoreEvaluation(assessableCourseNode, scoreEval, assessedUserCourseEnv,
+				getIdentity(), false, Role.coach);
 
 		if (isHasComment() && isUserCommentDirty()) {
 			String newComment = getUserComment().getValue();
-			// Update properties in db
-			assessableCourseNode.updatedUserComment(newComment, assessedUserCourseEnv, getIdentity());
+			courseAssessmentService.updatedUserComment(assessableCourseNode, newComment, assessedUserCourseEnv, getIdentity());
 		}
 
 		if (isCoachCommentDirty()) {
 			String newCoachComment = getCoachComment().getValue();
-			// Update properties in db
-			assessableCourseNode.updateCoachComment(newCoachComment, assessedUserCourseEnv);
+			courseAssessmentService.updateCoachComment(assessableCourseNode, newCoachComment, assessedUserCourseEnv);
 		}
 	}
 	
@@ -408,7 +417,7 @@ public class AssessmentForm extends FormBasicController {
 		if (scoreEval == null) scoreEval = new ScoreEvaluation(null, null);
 		
 		if (hasAttempts) {
-			attemptsValue = assessableCourseNode.getUserAttempts(assessedUserCourseEnv);
+			attemptsValue = courseAssessmentService.getUserAttempts(assessableCourseNode, assessedUserCourseEnv);
 			attempts.setIntValue(attemptsValue == null ? 0 : attemptsValue.intValue());
 		}
 		
@@ -427,7 +436,7 @@ public class AssessmentForm extends FormBasicController {
 		}
 		
 		if(hasComment) {
-			userCommentValue = assessableCourseNode.getUserComment(assessedUserCourseEnv);
+			userCommentValue = courseAssessmentService.getUserComment(assessableCourseNode, assessedUserCourseEnv);
 			userComment.setValue(userCommentValue);
 		}
 		
@@ -438,7 +447,8 @@ public class AssessmentForm extends FormBasicController {
 	private void reloadAssessmentDocs() {
 		if(docsLayoutCont == null) return;
 		
-		List<File> documents = assessableCourseNode.getIndividualAssessmentDocuments(assessedUserCourseEnv);
+		List<File> documents = courseAssessmentService.getIndividualAssessmentDocuments(assessableCourseNode,
+				assessedUserCourseEnv);
 		List<DocumentWrapper> wrappers = new ArrayList<>(documents.size());
 		for (File document : documents) {
 			DocumentWrapper wrapper = new DocumentWrapper(document);
@@ -506,7 +516,7 @@ public class AssessmentForm extends FormBasicController {
 		}
 
 		if (hasAttempts) {
-			attemptsValue = assessableCourseNode.getUserAttempts(assessedUserCourseEnv);
+			attemptsValue = courseAssessmentService.getUserAttempts(assessableCourseNode, assessedUserCourseEnv);
 			if(attemptsValue == null) {
 				attemptsValue = new Integer(0);
 			}
@@ -568,8 +578,7 @@ public class AssessmentForm extends FormBasicController {
 		}
 
 		if (hasComment) {
-			// Use init variables from db, not available from wrapper
-			userCommentValue = assessableCourseNode.getUserComment(assessedUserCourseEnv);
+			userCommentValue = courseAssessmentService.getUserComment(assessableCourseNode, assessedUserCourseEnv);
 			userComment = uifactory.addTextAreaElement("usercomment", "form.usercomment", 2500, 5, 40, true, false, userCommentValue, formLayout);
 			userComment.setNotLongerThanCheck(2500, "input.toolong");
 		}
@@ -586,7 +595,7 @@ public class AssessmentForm extends FormBasicController {
 			uploadDocsEl.addActionListener(FormEvent.ONCHANGE);
 		}
 		
-		coachCommentValue = assessableCourseNode.getCoachComment(assessedUserCourseEnv);
+		coachCommentValue = courseAssessmentService.getCoachComment(assessableCourseNode, assessedUserCourseEnv);
 		coachComment = uifactory.addTextAreaElement("coachcomment", "form.coachcomment", 2500, 5, 40, true, false, coachCommentValue, formLayout);
 		coachComment.setNotLongerThanCheck(2500, "input.toolong");
 		
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentIdentityCourseNodeController.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentIdentityCourseNodeController.java
index 3e7f4bb44b98580f28e1b621ab6dac56166e85ed..40cc2617e9423f0587f301e147d4d63331538121 100644
--- a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentIdentityCourseNodeController.java
+++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentIdentityCourseNodeController.java
@@ -45,6 +45,7 @@ import org.olat.core.util.coordinate.LockResult;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentModule;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.OpenSubDetailsEvent;
 import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.nodes.CourseNode;
@@ -84,6 +85,8 @@ public class AssessmentIdentityCourseNodeController extends BasicController impl
 	
 	@Autowired
 	private BaseSecurity securityManager;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	public AssessmentIdentityCourseNodeController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
 			RepositoryEntry courseEntry, CourseNode courseNode, UserCourseEnvironment coachCourseEnv,
@@ -132,7 +135,7 @@ public class AssessmentIdentityCourseNodeController extends BasicController impl
 			listenTo(assessmentForm);
 			identityAssessmentVC.put("assessmentForm", assessmentForm.getInitialComponent());
 			
-			String nodeLog = aCourseNode.getUserLog(assessedUserCourseEnvironment);
+			String nodeLog = courseAssessmentService.getUserLog(aCourseNode, assessedUserCourseEnvironment);
 			if(StringHelper.containsNonWhitespace(nodeLog)) {
 				identityAssessmentVC.contextPut("log", nodeLog);
 			}
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java
index 4f0f4916f4325ba657f1d11534c2dc01c179e4e4..a7e9928a707d32badeec00cdd26fd811bfb3472c 100644
--- a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java
+++ b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java
@@ -73,6 +73,7 @@ import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentModule;
 import org.olat.course.assessment.AssessmentToolManager;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.bulk.PassedCellRenderer;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.model.SearchAssessedIdentityParams;
@@ -157,6 +158,8 @@ public class IdentityListCourseNodeController extends FormBasicController
 	@Autowired
 	private CoordinatorManager coordinatorManager;
 	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+	@Autowired
 	private AssessmentToolManager assessmentToolManager;
 	
 	public IdentityListCourseNodeController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
@@ -846,7 +849,8 @@ public class IdentityListCourseNodeController extends FormBasicController
 			ScoreEvaluation doneEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(),
 					scoreEval.getAssessmentStatus(), visibility, scoreEval.getFullyAssessed(),
 					scoreEval.getCurrentRunCompletion(), scoreEval.getCurrentRunStatus(), scoreEval.getAssessmentID());
-			assessableCourseNode.updateUserScoreEvaluation(doneEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+			courseAssessmentService.updateUserScoreEvaluation(assessableCourseNode, doneEval, assessedUserCourseEnv,
+					getIdentity(), false, Role.coach);
 		}
 		loadModel(ureq);
 	}
@@ -885,7 +889,8 @@ public class IdentityListCourseNodeController extends FormBasicController
 		ScoreEvaluation doneEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(),
 				AssessmentEntryStatus.done, null, scoreEval.getFullyAssessed(),
 				scoreEval.getCurrentRunCompletion(), scoreEval.getCurrentRunStatus(), scoreEval.getAssessmentID());
-		assessableCourseNode.updateUserScoreEvaluation(doneEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+		courseAssessmentService.updateUserScoreEvaluation(assessableCourseNode, doneEval, assessedUserCourseEnv,
+				getIdentity(), false, Role.coach);
 		
 	}
 	
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/tools/AbstractToolsController.java b/src/main/java/org/olat/course/assessment/ui/tool/tools/AbstractToolsController.java
index 1c4805511e1b476f583816a59fe917a45e396c30..4be2af496b890bd52a54028fd0779a82415c5169 100644
--- a/src/main/java/org/olat/course/assessment/ui/tool/tools/AbstractToolsController.java
+++ b/src/main/java/org/olat/course/assessment/ui/tool/tools/AbstractToolsController.java
@@ -36,6 +36,7 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle
 import org.olat.core.id.Identity;
 import org.olat.core.util.Util;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.ui.tool.IdentityListCourseNodeController;
 import org.olat.course.assessment.ui.tool.event.ShowDetailsEvent;
 import org.olat.course.nodes.AssessableCourseNode;
@@ -46,6 +47,7 @@ import org.olat.modules.assessment.Role;
 import org.olat.modules.assessment.model.AssessmentEntryStatus;
 import org.olat.modules.assessment.model.AssessmentRunStatus;
 import org.olat.repository.RepositoryEntry;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -77,6 +79,9 @@ public abstract class AbstractToolsController extends BasicController {
 	protected final AssessableCourseNode courseNode;
 	protected final UserCourseEnvironment assessedUserCourseEnv;
 	
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+	
 	public AbstractToolsController(UserRequest ureq, WindowControl wControl,
 			AssessableCourseNode courseNode, Identity assessedIdentity, UserCourseEnvironment coachCourseEnv) {
 		super(ureq, wControl);
@@ -236,7 +241,8 @@ public abstract class AbstractToolsController extends BasicController {
 				AssessmentEntryStatus.inReview, scoreEval.getUserVisible(), scoreEval.getFullyAssessed(),
 				scoreEval.getCurrentRunCompletion(), AssessmentRunStatus.running,
 				scoreEval.getAssessmentID());
-		courseNode.updateUserScoreEvaluation(reopenedEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+		courseAssessmentService.updateUserScoreEvaluation(courseNode, reopenedEval, assessedUserCourseEnv,
+				getIdentity(), false, Role.coach);
 	}
 	
 	private void doSetDone(UserRequest ureq) {
@@ -251,7 +257,8 @@ public abstract class AbstractToolsController extends BasicController {
 				AssessmentEntryStatus.done, scoreEval.getUserVisible(), scoreEval.getFullyAssessed(),
 				scoreEval.getCurrentRunCompletion(), scoreEval.getCurrentRunStatus(),
 				scoreEval.getAssessmentID());
-		courseNode.updateUserScoreEvaluation(doneEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+		courseAssessmentService.updateUserScoreEvaluation(courseNode, doneEval, assessedUserCourseEnv, getIdentity(),
+				false, Role.coach);
 	}
 	
 	private void doSetVisibility(UserRequest ureq, boolean visible) {
@@ -260,7 +267,8 @@ public abstract class AbstractToolsController extends BasicController {
 					AssessmentEntryStatus.done, visible, scoreEval.getFullyAssessed(),
 					scoreEval.getCurrentRunCompletion(), scoreEval.getCurrentRunStatus(),
 					scoreEval.getAssessmentID());
-			courseNode.updateUserScoreEvaluation(doneEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+			courseAssessmentService.updateUserScoreEvaluation(courseNode, doneEval, assessedUserCourseEnv,
+					getIdentity(), false, Role.coach);
 		}
 		fireEvent(ureq, Event.CHANGED_EVENT);
 	}
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/tools/ResetAttemptsConfirmationController.java b/src/main/java/org/olat/course/assessment/ui/tool/tools/ResetAttemptsConfirmationController.java
index c59f9ec21291c1f54cbe963cb54dc51a8044b4c7..cc743b9f56c9ae1b9d689d871940141730294d37 100644
--- a/src/main/java/org/olat/course/assessment/ui/tool/tools/ResetAttemptsConfirmationController.java
+++ b/src/main/java/org/olat/course/assessment/ui/tool/tools/ResetAttemptsConfirmationController.java
@@ -28,11 +28,13 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.Identity;
 import org.olat.core.util.Util;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.ui.tool.IdentityListCourseNodeController;
 import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.modules.assessment.Role;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -46,6 +48,9 @@ public class ResetAttemptsConfirmationController extends FormBasicController {
 	private final CourseEnvironment courseEnv;
 	private final AssessableCourseNode courseNode;
 	
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+	
 	public ResetAttemptsConfirmationController(UserRequest ureq, WindowControl wControl,
 			CourseEnvironment courseEnv, AssessableCourseNode courseNode, Identity assessedIdentity) {
 		super(ureq, wControl, "reset_attempts", Util.createPackageTranslator(IdentityListCourseNodeController.class, ureq.getLocale()));
@@ -71,7 +76,8 @@ public class ResetAttemptsConfirmationController extends FormBasicController {
 		AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, courseEnv);
 		UserCourseEnvironment assessedUserCourseEnv = AssessmentHelper
 				.createAndInitUserCourseEnvironment(assessedIdentity, courseEnv);
-		courseNode.updateUserAttempts(new Integer(0), assessedUserCourseEnv, getIdentity(), Role.coach);
+		courseAssessmentService.updateUserAttempts(courseNode, Integer.valueOf(0), assessedUserCourseEnv, getIdentity(),
+				Role.coach);
 		fireEvent(ureq, Event.CHANGED_EVENT);
 	}
 
diff --git a/src/main/java/org/olat/course/nodes/CourseNode.java b/src/main/java/org/olat/course/nodes/CourseNode.java
index 71c7198318d8510a9642fe53b50c07dd977a27a1..81a5aa06734ccf1692b09c876cd19320c58fbdeb 100644
--- a/src/main/java/org/olat/course/nodes/CourseNode.java
+++ b/src/main/java/org/olat/course/nodes/CourseNode.java
@@ -49,7 +49,6 @@ import org.olat.course.editor.PublishEvents;
 import org.olat.course.editor.StatusDescription;
 import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.course.run.navigation.NodeRunConstructionResult;
-import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.NodeEvaluation;
 import org.olat.course.run.userview.TreeEvaluation;
 import org.olat.course.run.userview.TreeFilter;
@@ -58,8 +57,6 @@ import org.olat.course.statistic.StatisticResourceOption;
 import org.olat.course.statistic.StatisticResourceResult;
 import org.olat.course.statistic.StatisticType;
 import org.olat.modules.ModuleConfiguration;
-import org.olat.modules.assessment.Role;
-import org.olat.modules.assessment.model.AssessmentRunStatus;
 import org.olat.repository.RepositoryEntry;
 
 /**
@@ -448,117 +445,7 @@ public interface CourseNode extends INode, ShortName {
 	public void updateModuleConfigDefaults(boolean isNewNode);
 	
 	
-	// Assessment methods
-	
 	public AssessmentConfig getAssessmentConfig();
-
-	public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment,
-			Identity coachingIdentity, boolean incrementAttempts, Role by);
-	
-	/**
-	 * @param userCourseEnvironment
-	 * @return The completion of its current task before being committed and official.
-	 */
-	public Double getUserCurrentRunCompletion(UserCourseEnvironment userCourseEnvironment);
-	
-	public void updateCurrentCompletion(UserCourseEnvironment userCourseEnvironment, Identity identity,
-			Double currentCompletion, AssessmentRunStatus status, Role doneBy);
-	
-	/**
-	 * @param userCourseEnvironment
-	 * @return the users attempts of this node
-	 */
-	public Integer getUserAttempts(UserCourseEnvironment userCourseEnvironment);
-	
-	/**
-	 * Increments the users attempts for this node and this user.
-	 *
-	 * @param userCourseEnvironment
-	 * @param doneBy
-	 */
-	public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role doneBy);
-	
-	/**
-	 * Updates the users attempts for this node and this user. 
-	 *
-	 * @param userAttempts
-	 * @param userCourseEnvironment
-	 * @param coachingIdentity
-	 * @param doneBy
-	 */
-	public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment,
-			Identity coachingIdentity, Role doneBy);
-
-	/**
-	 * @param userCourseEnvironment
-	 * @return the user comment for this user for this node, given by coach
-	 */
-	public String getUserComment(UserCourseEnvironment userCourseEnvironment);
-	
-	/**
-	 * Updates the user comment for this node and this user. This comment is visible to the user.
-	 * 
-	 * @param userComment
-	 * @param userCourseEnvironment
-	 * @param coachingIdentity
-	 */
-	public void updatedUserComment(String userComment, UserCourseEnvironment userCourseEnvironment,
-			Identity coachingIdentity);
-	
-	/**
-	 * @param userCourseEnvironment
-	 * @return The coach comment for this user for this node (not visible to user)
-	 */
-	public String getCoachComment(UserCourseEnvironment userCourseEnvironment);
-	
-	/**
-	 * Updates the coach comment for this node and this user. This comment is not visible to the user.
-	 * 
-	 * @param coachComment
-	 * @param userCourseEnvironment
-	 */
-	public void updateCoachComment(String coachComment, UserCourseEnvironment userCourseEnvironment);
-	
-	
-	/**
-	 * @param userCourseEnvironment The course environment of the assessed user.
-	 * @return The list of assessment document associated with this user and course element.
-	 */
-	public List<File> getIndividualAssessmentDocuments(UserCourseEnvironment userCourseEnvironment);
-	
-	/**
-	 * Add a document for the assessed user, if allowed.
-	 * 
-	 * @param document The document
-	 * @param userCourseEnvironment The course environment of the assessed user
-	 * @param coachingIdentity The coach who upload the document
-	 */
-	public void addIndividualAssessmentDocument(File document, String filename,
-			UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity);
-	
-	/**
-	 * Remove a document.
-	 * 
-	 * @param document The document to remove
-	 * @param userCourseEnvironment The course environment of the assessed user
-	 * @param coachingIdentity The coach who delete the document
-	 */
-	public void removeIndividualAssessmentDocument(File document, UserCourseEnvironment userCourseEnvironment,
-			Identity coachingIdentity);
-	
-	/**
-	 * 
-	 * @param userCourseEnvironment The user course environment of the assessed identity
-	 * @param identity The identity which do the action
-	 * @param doneBy The role of the identity which do the action
-	 */
-	public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role doneBy);
-	
-	/**
-	 * @param userCourseEnvironment
-	 * @return the users log of this node
-	 */
-	public String getUserLog(UserCourseEnvironment userCourseEnvironment);
 	
 	public enum Processing {
 		runstructure,
diff --git a/src/main/java/org/olat/course/nodes/GenericCourseNode.java b/src/main/java/org/olat/course/nodes/GenericCourseNode.java
index 5c752234008809cdffb6f1fd9aa06ba98108f3a3..451c42a663d3cf1073165674cec69128ee453994 100644
--- a/src/main/java/org/olat/course/nodes/GenericCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/GenericCourseNode.java
@@ -47,10 +47,8 @@ import org.olat.core.util.Util;
 import org.olat.core.util.nodes.GenericNode;
 import org.olat.core.util.xml.XStreamHelper;
 import org.olat.course.ICourse;
-import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.handler.NonAssessmentConfig;
-import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.condition.Condition;
 import org.olat.course.condition.KeyAndNameConverter;
 import org.olat.course.condition.additionalconditions.AdditionalCondition;
@@ -63,7 +61,6 @@ import org.olat.course.editor.PublishEvents;
 import org.olat.course.editor.StatusDescription;
 import org.olat.course.export.CourseEnvironmentMapper;
 import org.olat.course.run.navigation.NodeRunConstructionResult;
-import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.NodeEvaluation;
 import org.olat.course.run.userview.TreeEvaluation;
 import org.olat.course.run.userview.TreeFilter;
@@ -72,8 +69,6 @@ import org.olat.course.statistic.StatisticResourceOption;
 import org.olat.course.statistic.StatisticResourceResult;
 import org.olat.course.statistic.StatisticType;
 import org.olat.modules.ModuleConfiguration;
-import org.olat.modules.assessment.Role;
-import org.olat.modules.assessment.model.AssessmentRunStatus;
 
 /**
  * Description:<br>
@@ -686,124 +681,5 @@ public abstract class GenericCourseNode extends GenericNode implements CourseNod
 	public AssessmentConfig getAssessmentConfig() {
 		return NonAssessmentConfig.create();
 	}
-	
-	@Override
-	public void updateUserScoreEvaluation(ScoreEvaluation scoreEvaluation, UserCourseEnvironment userCourseEnvironment,
-			Identity coachingIdentity, boolean incrementAttempts, Role by) {
-		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-		am.saveScoreEvaluation(this, coachingIdentity, assessedIdentity, new ScoreEvaluation(scoreEvaluation),
-				userCourseEnvironment, incrementAttempts, by);
-	}
-
-	@Override
-	public Double getUserCurrentRunCompletion(UserCourseEnvironment userCourseEnvironment) {
-		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-		return am.getNodeCurrentRunCompletion(this, assessedIdentity);
-	}
-	
-	@Override
-	public void updateCurrentCompletion(UserCourseEnvironment userCourseEnvironment, Identity identity,
-			Double currentCompletion, AssessmentRunStatus runStatus, Role doneBy) {
-		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-		am.updateCurrentCompletion(this, assessedIdentity, userCourseEnvironment, currentCompletion, runStatus, doneBy);
-	}
-	
-	@Override
-	public Integer getUserAttempts(UserCourseEnvironment userCourseEnv) {
-		AssessmentManager am = userCourseEnv.getCourseEnvironment().getAssessmentManager();
-		Identity assessedIdentity = userCourseEnv.getIdentityEnvironment().getIdentity();
-		return am.getNodeAttempts(this, assessedIdentity);
-	}
-	
-	@Override
-	public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) {
-		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-		am.incrementNodeAttempts(this, assessedIdentity, userCourseEnvironment, by);
-	}
-	
-	@Override
-	public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) {
-		if (userAttempts != null) {
-			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-			am.saveNodeAttempts(this, coachingIdentity, assessedIdentity, userAttempts, by);
-		}
-	}
-
-	@Override
-	public String getUserComment(UserCourseEnvironment userCourseEnvironment) {
-		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-		return am.getNodeComment(this, assessedIdentity);
-	}
-	
-	@Override
-	public void updatedUserComment(String userComment, UserCourseEnvironment userCourseEnvironment,
-			Identity coachingIdentity) {
-		if (userComment != null) {
-			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-			am.saveNodeComment(this, coachingIdentity, assessedIdentity, userComment);
-		}
-	}
-	
-	@Override
-	public String getCoachComment(UserCourseEnvironment userCourseEnvironment) {
-		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-		return am.getNodeCoachComment(this, assessedIdentity);
-	}
-	
-	@Override
-	public void updateCoachComment(String coachComment, UserCourseEnvironment userCourseEnvironment) {
-		if (coachComment != null) {
-			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-			am.saveNodeCoachComment(this, assessedIdentity, coachComment);
-		}
-	}
-	
-	@Override
-	public List<File> getIndividualAssessmentDocuments(UserCourseEnvironment userCourseEnvironment) {
-		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-		return am.getIndividualAssessmentDocuments(this, assessedIdentity);
-	}
-	
-	@Override
-	public void addIndividualAssessmentDocument(File document, String filename, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) {
-		if(document != null) {
-			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-			am.addIndividualAssessmentDocument(this, coachingIdentity, assessedIdentity, document, filename);
-		}
-	}
-
-	@Override
-	public void removeIndividualAssessmentDocument(File document, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity) {
-		if(document != null) {
-			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-			Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-			am.removeIndividualAssessmentDocument(this, coachingIdentity, assessedIdentity, document);
-		}
-	}
-	
-	@Override
-	public void updateLastModifications(UserCourseEnvironment userCourseEnvironment, Identity identity, Role by) {
-		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
-		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-		am.updateLastModifications(this, assessedIdentity, userCourseEnvironment, by);
-	}
-	
-	@Override
-	public String getUserLog(UserCourseEnvironment userCourseEnvironment) {
-		UserNodeAuditManager am = userCourseEnvironment.getCourseEnvironment().getAuditManager();
-		Identity assessedIdentity = userCourseEnvironment.getIdentityEnvironment().getIdentity();
-		return am.getUserNodeLog(this, assessedIdentity);
-	}
 
 }
diff --git a/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java b/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java
index da475a142a0eb3085fb5d5be081e0b5ffeee81ef..f933f964d8d9a7e582b2014fc5fa8704e8c8f6c6 100644
--- a/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/IQSELFCourseNode.java
@@ -395,7 +395,7 @@ public class IQSELFCourseNode extends AbstractAccessableCourseNode implements Se
 	}
 	
 	@Override
-	public Integer getUserAttempts(UserCourseEnvironment userCourseEnvironment) {
+	public Integer getUserAttempts(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
 		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity();
 		return am.getNodeAttempts(this, mySelf);
@@ -405,7 +405,7 @@ public class IQSELFCourseNode extends AbstractAccessableCourseNode implements Se
 	 * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment)
 	 */
 	@Override
-	public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) {
+	public void incrementUserAttempts(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment, Role by) {
 		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity();
 		am.incrementNodeAttempts(this, mySelf, userCourseEnvironment, by);
diff --git a/src/main/java/org/olat/course/nodes/IQSURVCourseNode.java b/src/main/java/org/olat/course/nodes/IQSURVCourseNode.java
index f966c9816171bff92b1ed829e72119bfe83281ba..9926995c8771a26859a0deb3594affa0a1a308d3 100644
--- a/src/main/java/org/olat/course/nodes/IQSURVCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/IQSURVCourseNode.java
@@ -367,9 +367,9 @@ public class IQSURVCourseNode extends AbstractAccessableCourseNode implements QT
 	}
 
 	/**
-	 * @see org.olat.course.nodes.AssessableCourseNode#getUserAttempts(org.olat.course.run.userview.UserCourseEnvironment)
+	 * @see org.olat.course.nodes.AssessableCourseNode#getUserAttempts(CourseNode, org.olat.course.run.userview.UserCourseEnvironment)
 	 */
-	public Integer getUserAttempts(UserCourseEnvironment userCourseEnvironment) {
+	public Integer getUserAttempts(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment) {
 		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity();
 		Integer userAttemptsValue = am.getNodeAttempts(this, mySelf);
@@ -390,7 +390,7 @@ public class IQSURVCourseNode extends AbstractAccessableCourseNode implements QT
 	 *      org.olat.course.run.userview.UserCourseEnvironment,
 	 *      org.olat.core.id.Identity)
 	 */
-	public void updateUserAttempts(Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) {
+	public void updateUserAttempts(CourseNode courseNode, Integer userAttempts, UserCourseEnvironment userCourseEnvironment, Identity coachingIdentity, Role by) {
 		if (userAttempts != null) {
 			AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
 			Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity();
@@ -401,7 +401,7 @@ public class IQSURVCourseNode extends AbstractAccessableCourseNode implements QT
 	/**
 	 * @see org.olat.course.nodes.AssessableCourseNode#incrementUserAttempts(org.olat.course.run.userview.UserCourseEnvironment)
 	 */
-	public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by) {
+	public void incrementUserAttempts(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment, Role by) {
 		AssessmentManager am = userCourseEnvironment.getCourseEnvironment().getAssessmentManager();
 		Identity mySelf = userCourseEnvironment.getIdentityEnvironment().getIdentity();
 		am.incrementNodeAttempts(this, mySelf, userCourseEnvironment, by);
diff --git a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
index 987016e86fe9ff2c8c364319918187c9d41de8f3..80fe066b9caa0e1c0a905b448216326117df59a0 100644
--- a/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/IQTESTCourseNode.java
@@ -55,6 +55,7 @@ import org.olat.core.util.resource.OresHelper;
 import org.olat.course.ICourse;
 import org.olat.course.archiver.ScoreAccountingHelper;
 import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.ui.tool.AssessmentCourseNodeController;
 import org.olat.course.editor.CourseEditorEnv;
@@ -586,9 +587,10 @@ public class IQTESTCourseNode extends AbstractAccessableCourseNode implements Pe
 			assessmentStatus = AssessmentEntryStatus.done;
 			visibility = Boolean.TRUE;
 		}
+		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 		ScoreEvaluation sceval = new ScoreEvaluation(session.getScore().floatValue(), session.getPassed(), assessmentStatus, visibility, Boolean.TRUE,
 				1.0d, AssessmentRunStatus.done, session.getKey());
-		updateUserScoreEvaluation(sceval, assessedUserCourseenv, coachingIdentity, true, by);
+		courseAssessmentService.updateUserScoreEvaluation(this, sceval, assessedUserCourseenv, coachingIdentity, true, by);
 	}
 
 	/**
diff --git a/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java b/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java
index f2332b4da5f26f10804388bd33fba9c4b92dbf6c..daef634936acebfa60804a11892b38c814da1259 100644
--- a/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/SelfAssessableCourseNode.java
@@ -51,12 +51,12 @@ public interface SelfAssessableCourseNode extends CourseNode {
 	 * @param userCourseEnvironment
 	 * @return The users attempts of this node
 	 */
-	public Integer getUserAttempts(UserCourseEnvironment userCourseEnvironment);
+	public Integer getUserAttempts(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment);
 	
 	/**
 	 * Increments the users attempts for this node and this user + 1. 
 	 * @param userCourseEnvironment
 	 */
-	public void incrementUserAttempts(UserCourseEnvironment userCourseEnvironment, Role by);
+	public void incrementUserAttempts(CourseNode courseNode, UserCourseEnvironment userCourseEnvironment, Role by);
 	
 }
diff --git a/src/main/java/org/olat/course/nodes/TACourseNode.java b/src/main/java/org/olat/course/nodes/TACourseNode.java
index 4a3d8cc1cdf6f1dc12bfd78ee31157a6250cf60f..1c87d737aeb674bcdf4038f44a2923643927f2fa 100644
--- a/src/main/java/org/olat/course/nodes/TACourseNode.java
+++ b/src/main/java/org/olat/course/nodes/TACourseNode.java
@@ -480,7 +480,6 @@ public class TACourseNode extends GenericCourseNode implements PersistentAssessa
 		return am.getAssessmentEntry(this, mySelf);
 	}
 
-	@Override
 	//TODO uh anders als die Default Implemntation notwendig?
 	public void updateUserScoreEvaluation(ScoreEvaluation scoreEval, UserCourseEnvironment userCourseEnvironment,
 			Identity coachingIdentity, boolean incrementAttempts, Role by) {
diff --git a/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java b/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java
index ec24d34929db4bcb7f8c82a7607346810fb0f4e2..0e13a07c603b1f782f0964e7d1541179fd00173f 100644
--- a/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java
+++ b/src/main/java/org/olat/course/nodes/basiclti/CourseNodeOutcomeMapper.java
@@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest;
 
 import org.imsglobal.basiclti.XMLMap;
 import org.imsglobal.pox.IMSPOXRequest;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.logging.activity.IUserActivityLogger;
@@ -33,6 +34,7 @@ import org.olat.core.logging.activity.ThreadLocalUserActivityLoggerInstaller;
 import org.olat.core.logging.activity.UserActivityLoggerImpl;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.nodes.BasicLTICourseNode;
 import org.olat.course.nodes.CourseNode;
@@ -86,8 +88,8 @@ public class CourseNodeOutcomeMapper extends OutcomeMapper {
 		ICourse course = CourseFactory.loadCourse(courseOresId);
 		CourseNode node = course.getRunStructure().getNode(courseNodeId);
 		if(node instanceof BasicLTICourseNode) {
-			BasicLTICourseNode ltiNode = (BasicLTICourseNode)node;
-			AssessmentConfig assessmentConfig = ltiNode.getAssessmentConfig();
+			CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+			AssessmentConfig assessmentConfig = node.getAssessmentConfig();
 			
 			Identity assessedId = getIdentity();
 			Float cutValue = getCutValue(assessmentConfig);
@@ -95,7 +97,7 @@ public class CourseNodeOutcomeMapper extends OutcomeMapper {
 			Float scaledScore = null;
 			Boolean passed = null;
 			if(score != null) {
-				float scale = getScalingFactor(ltiNode);
+				float scale = getScalingFactor(node);
 				scaledScore = score * scale;
 				if(cutValue != null) {
 					passed = scaledScore >= cutValue;
@@ -104,7 +106,7 @@ public class CourseNodeOutcomeMapper extends OutcomeMapper {
 			
 			ScoreEvaluation eval = new ScoreEvaluation(scaledScore, passed);
 			UserCourseEnvironment userCourseEnv = getUserCourseEnvironment(course);
-			ltiNode.updateUserScoreEvaluation(eval, userCourseEnv, assessedId, false, Role.user);
+			courseAssessmentService.updateUserScoreEvaluation(node, eval, userCourseEnv, assessedId, false, Role.user);
 		}
 		
 		return super.doUpdateResult(score);
@@ -115,11 +117,11 @@ public class CourseNodeOutcomeMapper extends OutcomeMapper {
 		ICourse course = CourseFactory.loadCourse(courseOresId);
 		CourseNode node = course.getRunStructure().getNode(courseNodeId);
 		if(node instanceof BasicLTICourseNode) {
-			BasicLTICourseNode ltiNode = (BasicLTICourseNode)node;
+			CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 			Identity assessedId = getIdentity();
 			ScoreEvaluation eval = new ScoreEvaluation(0.0f, false);
 			UserCourseEnvironment userCourseEnv = getUserCourseEnvironment(course);
-			ltiNode.updateUserScoreEvaluation(eval, userCourseEnv, assessedId, false, Role.user);
+			courseAssessmentService.updateUserScoreEvaluation(node, eval, userCourseEnv, assessedId, false, Role.user);
 		}
 
 		return super.doDeleteResult();
@@ -159,9 +161,9 @@ public class CourseNodeOutcomeMapper extends OutcomeMapper {
 		return userCourseEnv;
 	}
 	
-	private float getScalingFactor(BasicLTICourseNode ltiNode) {
-		if(ltiNode.getAssessmentConfig().hasScore()) {
-			Float scale = ltiNode.getModuleConfiguration().getFloatEntry(BasicLTICourseNode.CONFIG_KEY_SCALEVALUE);
+	private float getScalingFactor(CourseNode node) {
+		if(node.getAssessmentConfig().hasScore()) {
+			Float scale = node.getModuleConfiguration().getFloatEntry(BasicLTICourseNode.CONFIG_KEY_SCALEVALUE);
 			if(scale == null) {
 				return 1.0f;
 			}
diff --git a/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java b/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java
index e5c3910aa126581dc14dc6cd0dd5bc210f82e4f0..f18e2ac96130cf818664299feb769243250daa6f 100644
--- a/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java
+++ b/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java
@@ -53,6 +53,7 @@ import org.olat.core.util.Encoder;
 import org.olat.core.util.SortedProperties;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.highscore.ui.HighScoreRunController;
 import org.olat.course.nodes.BasicLTICourseNode;
 import org.olat.course.nodes.CourseNode;
@@ -106,6 +107,8 @@ public class LTIRunController extends BasicController {
 	private LTIModule ltiModule;
 	@Autowired
 	private LTIManager ltiManager;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	public LTIRunController(WindowControl wControl, ModuleConfiguration config, UserRequest ureq, BasicLTICourseNode ltCourseNode,
 			CourseEnvironment courseEnv) {
@@ -336,7 +339,7 @@ public class LTIRunController extends BasicController {
 		if(assessable != null && assessable.booleanValue()) {
 			startPage.contextPut("isassessable", assessable);
 	    
-			Integer attempts = courseNode.getUserAttempts(userCourseEnv);
+			Integer attempts = courseAssessmentService.getUserAttempts(courseNode, userCourseEnv);
 			startPage.contextPut("attempts", attempts);
 	    
 			ScoreEvaluation eval = courseNode.getUserScoreEvaluation(userCourseEnv);
@@ -363,7 +366,7 @@ public class LTIRunController extends BasicController {
 			Boolean skipLaunchPage = config.getBooleanEntry(BasicLTICourseNode.CONFIG_SKIP_LAUNCH_PAGE);
 			if(!ltiModule.isForceLaunchPage() && skipLaunchPage != null && skipLaunchPage.booleanValue()) {
 				// start the content immediately
-				courseNode.incrementUserAttempts(userCourseEnv, Role.user);
+				courseAssessmentService.incrementUserAttempts(courseNode, userCourseEnv, Role.user);
 				openBasicLTIContent(ureq);
 			} else {
 				// or show the start button
@@ -403,7 +406,7 @@ public class LTIRunController extends BasicController {
 	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if(source == startButton) {
-			courseNode.incrementUserAttempts(userCourseEnv, Role.user);
+			courseAssessmentService.incrementUserAttempts(courseNode, userCourseEnv, Role.user);
 			openBasicLTIContent(ureq);
 		} else if (source == acceptLink) {
 			storeDataExchangeAcceptance();
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java
index 0254fb5a50516fcf6645a0510c00e0865072b346..85da23a68228ceeaa6bfb860f818242bfe43a82b 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListRunController.java
@@ -55,6 +55,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.highscore.ui.HighScoreRunController;
@@ -96,6 +97,8 @@ public class CheckListRunController extends FormBasicController implements Contr
 	
 	@Autowired
 	private CheckboxManager checkboxManager;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	/**
 	 * Use this constructor to launch the checklist.
@@ -221,7 +224,7 @@ public class CheckListRunController extends FormBasicController implements Contr
 					layoutCont.contextPut("incomment", isPanelOpen(ureq, "comment", true));
 				}
 				if(assessmentConfig.hasIndividualAsssessmentDocuments()) {
-					List<File> docs = courseNode.getIndividualAssessmentDocuments(userCourseEnv);
+					List<File> docs = courseAssessmentService.getIndividualAssessmentDocuments(courseNode, userCourseEnv);
 					String mapperUri = registerCacheableMapper(ureq, null, new DocumentsMapper(docs));
 					layoutCont.contextPut("docsMapperUri", mapperUri);
 					layoutCont.contextPut("docs", docs);
diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
index 2d80e25fcce44ebee08fdf3445eae60f6393ee1c..2fb96d7accb082af6482d44897ae5acb5df07299 100644
--- a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
+++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
@@ -37,6 +37,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import javax.persistence.LockModeType;
 import javax.persistence.Query;
 
+import org.apache.logging.log4j.Logger;
 import org.hibernate.LazyInitializationException;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.basesecurity.IdentityRef;
@@ -46,7 +47,6 @@ import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.commons.services.notifications.PublisherData;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
 import org.olat.core.id.Identity;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.StringHelper;
@@ -58,6 +58,7 @@ import org.olat.core.util.xml.XStreamHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.manager.UserCourseInformationsManager;
 import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.nodes.gta.AssignmentResponse;
@@ -130,6 +131,8 @@ public class GTAManagerImpl implements GTAManager {
 	@Autowired
 	private BGAreaManager areaManager;
 	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+	@Autowired
 	private AssessmentService assessmentService;
 	@Autowired
 	private EdusharingService edusharingService;
@@ -1702,7 +1705,7 @@ public class GTAManagerImpl implements GTAManager {
 
 			ICourse course = CourseFactory.loadCourse(courseRepoEntry);
 			UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
-			cNode.updateLastModifications(userCourseEnv, taskImpl.getIdentity(), by);
+			courseAssessmentService.updateLastModifications(cNode, userCourseEnv, taskImpl.getIdentity(), by);
 		}
 	}
 
diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java b/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java
index f35b650e5cfa67c0e4cbb97b13931aac9d4c0c31..7043841920a20d3aa883f446c4a75361d95309bc 100644
--- a/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java
+++ b/src/main/java/org/olat/course/nodes/gta/manager/GTANotifications.java
@@ -51,6 +51,7 @@ import org.olat.core.util.vfs.VFSItem;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.GTACourseNode;
@@ -117,6 +118,8 @@ class GTANotifications {
 	@Autowired
 	private BusinessGroupService businessGroupService;
 	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+	@Autowired
 	private AssessmentEntryDAO courseNodeAssessmentDao;
 	
 	public GTANotifications(Subscriber subscriber, boolean markedOnly, Locale locale, Date compareDate) {
@@ -622,7 +625,8 @@ class GTANotifications {
 				ICourse course = CourseFactory.loadCourse(courseEnv.getCourseGroupManager().getCourseEntry());
 				UserCourseEnvironment assessedUserCourseEnv = AssessmentHelper
 						.createAndInitUserCourseEnvironment(assessedIdentity, course);
-				List<File> docs = gtaNode.getIndividualAssessmentDocuments(assessedUserCourseEnv);
+				List<File> docs = courseAssessmentService.getIndividualAssessmentDocuments(gtaNode,
+						assessedUserCourseEnv);
 				for(File doc:docs) {
 					String[] docParams = new String[] {
 							getTaskName(task),
@@ -821,17 +825,18 @@ class GTANotifications {
 	}
 	
 	private void doUpdateAttempts(Identity assessedIdentity, BusinessGroup assessedGroup) {
+		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 		ICourse course = CourseFactory.loadCourse(courseEnv.getCourseGroupManager().getCourseEntry());
 		if(GTAType.group.name().equals(gtaNode.getModuleConfiguration().getStringValue(GTACourseNode.GTASK_TYPE))) {
 			List<Identity> identities = businessGroupService.getMembers(assessedGroup, GroupRoles.participant.name());
 			for(Identity identity:identities) {
 				UserCourseEnvironment uce = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course);
-				gtaNode.incrementUserAttempts(uce, Role.auto);
+				courseAssessmentService.incrementUserAttempts(gtaNode, uce, Role.auto);
 			}
 		} else {
 			UserCourseEnvironment assessedUserCourseEnv = AssessmentHelper
 					.createAndInitUserCourseEnvironment(assessedIdentity, course);
-			gtaNode.incrementUserAttempts(assessedUserCourseEnv, Role.auto);
+			courseAssessmentService.incrementUserAttempts(gtaNode, assessedUserCourseEnv, Role.auto);
 		}
 	}
 	
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/EditCommentController.java b/src/main/java/org/olat/course/nodes/gta/ui/EditCommentController.java
index eee49431382d28602b5253a5f113859bb0607dc6..ee7ab7f2e2e006751d4cca558d49093e9a2d5552 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/EditCommentController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/EditCommentController.java
@@ -30,8 +30,10 @@ import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.StringHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.run.userview.UserCourseEnvironment;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -46,6 +48,9 @@ public class EditCommentController extends FormBasicController {
 	private final GTACourseNode gtaNode;
 	private final OLATResourceable courseOres;
 	
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+	
 	public EditCommentController(UserRequest ureq, WindowControl wControl,
 			OLATResourceable courseOres, GTACourseNode gtaNode, AssessmentRow row) {
 		super(ureq, wControl, "comment_callout");
@@ -76,7 +81,7 @@ public class EditCommentController extends FormBasicController {
 		
 		ICourse course = CourseFactory.loadCourse(courseOres);
 		UserCourseEnvironment userCourseEnv = row.getUserCourseEnvironment(course);
-		gtaNode.updatedUserComment(comment, userCourseEnv, getIdentity());
+		courseAssessmentService.updatedUserComment(gtaNode, comment, userCourseEnv, getIdentity());
 		
 		if(StringHelper.containsNonWhitespace(comment)) {
 			row.getCommentEditLink().setIconLeftCSS("o_icon o_icon_comments");
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAAbstractController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAAbstractController.java
index 9bcf898dff005ce16892d4a8084e9f0f2d0eb42d..ac8ba41a5f8fdf977b0c37ceae30f3b40f055796 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTAAbstractController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAAbstractController.java
@@ -46,6 +46,7 @@ import org.olat.course.CourseFactory;
 import org.olat.course.CourseModule;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.manager.UserCourseInformationsManager;
 import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.nodes.gta.GTAManager;
@@ -112,6 +113,8 @@ public abstract class GTAAbstractController extends BasicController implements G
 	protected UserCourseInformationsManager userCourseInformationsManager;
 	@Autowired
 	protected CourseModule courseModule;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	public GTAAbstractController(UserRequest ureq, WindowControl wControl,
 			GTACourseNode gtaNode, CourseEnvironment courseEnv, boolean withTitle, boolean withGrading, boolean withSubscription) {
@@ -485,11 +488,11 @@ public abstract class GTAAbstractController extends BasicController implements G
 			ICourse course = CourseFactory.loadCourse(courseEnv.getCourseGroupManager().getCourseEntry());
 			for(Identity identity:identities) {
 				UserCourseEnvironment uce = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course);
-				gtaNode.incrementUserAttempts(uce, by);
+				courseAssessmentService.incrementUserAttempts(gtaNode, uce, by);
 			}
 		} else {
 			UserCourseEnvironment assessedUserCourseEnv = getAssessedUserCourseEnvironment();
-			gtaNode.incrementUserAttempts(assessedUserCourseEnv, by);
+			courseAssessmentService.incrementUserAttempts(gtaNode, assessedUserCourseEnv, by);
 		}
 	}
 	
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java
index a70ad880f48e930f6185416b097a7bab89328d9e..912e7fe42454b3874b2bfc2b827c9b76b1da2874 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachRevisionAndCorrectionsController.java
@@ -50,6 +50,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.nodes.gta.GTAManager;
 import org.olat.course.nodes.gta.GTAType;
@@ -102,6 +103,8 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController im
 	private UserManager userManager;
 	@Autowired
 	private BusinessGroupService businessGroupService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	public GTACoachRevisionAndCorrectionsController(UserRequest ureq, WindowControl wControl, CourseEnvironment courseEnv,
 			Task assignedTask, GTACourseNode gtaNode, UserCourseEnvironment coachCourseEnv, BusinessGroup assessedGroup,
@@ -385,10 +388,10 @@ public class GTACoachRevisionAndCorrectionsController extends BasicController im
 			List<Identity> identities = businessGroupService.getMembers(assessedGroup, GroupRoles.participant.name());
 			for(Identity identity:identities) {
 				UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course);
-				gtaNode.incrementUserAttempts(userCourseEnv, Role.coach);
+				courseAssessmentService.incrementUserAttempts(gtaNode, userCourseEnv, Role.coach);
 			}
 		} else {
-			gtaNode.incrementUserAttempts(assessedUserCourseEnv, Role.coach);
+			courseAssessmentService.incrementUserAttempts(gtaNode, assessedUserCourseEnv, Role.coach);
 		}
 		
 		TaskMultiUserEvent event = new TaskMultiUserEvent(TaskMultiUserEvent.SUBMIT_REVISION,
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantRevisionAndCorrectionsController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantRevisionAndCorrectionsController.java
index b191d6a369c179b612791af336a28baa7bb8416d..50f76b443a409a5247229574744cbda72ebc3141 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantRevisionAndCorrectionsController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantRevisionAndCorrectionsController.java
@@ -58,6 +58,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.nodes.gta.GTAManager;
 import org.olat.course.nodes.gta.GTAType;
@@ -105,6 +106,8 @@ public class GTAParticipantRevisionAndCorrectionsController extends BasicControl
 	private MailManager mailManager;
 	@Autowired
 	private BusinessGroupService businessGroupService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	public GTAParticipantRevisionAndCorrectionsController(UserRequest ureq, WindowControl wControl,
 			UserCourseEnvironment assessedUserCourseEnv,Task assignedTask,
@@ -356,10 +359,10 @@ public class GTAParticipantRevisionAndCorrectionsController extends BasicControl
 
 			for(Identity identity:identities) {
 				UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(identity, course);
-				gtaNode.incrementUserAttempts(userCourseEnv, Role.user);
+				courseAssessmentService.incrementUserAttempts(gtaNode, userCourseEnv, Role.user);
 			}
 		} else {
-			gtaNode.incrementUserAttempts(assessedUserCourseEnv, Role.user);
+			courseAssessmentService.incrementUserAttempts(gtaNode, assessedUserCourseEnv, Role.user);
 		}
 		
 		//do send e-mail
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 0a5dd5c7d5d06bddea3a79ea1830fa7ecebca2d0..bc14f80872e90d615e4f9e12f730d43c2392eb7f 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
@@ -57,6 +57,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.nodes.gta.GTAManager;
@@ -113,6 +114,8 @@ public class GroupAssessmentController extends FormBasicController {
 	private BaseSecurityModule securityModule;
 	@Autowired
 	private BusinessGroupService businessGroupService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	private final List<Long> duplicateMemberKeys;
 	
@@ -555,12 +558,12 @@ public class GroupAssessmentController extends FormBasicController {
 			} else {
 				newScoreEval = new ScoreEvaluation(score, passed, null, userVisible, null, null, null, null);
 			}
-			gtaNode.updateUserScoreEvaluation(newScoreEval, userCourseEnv, getIdentity(), false, Role.coach);
+			courseAssessmentService.updateUserScoreEvaluation(gtaNode, newScoreEval, userCourseEnv, getIdentity(), false, Role.coach);
 			
 			if(withComment) {
 				String comment = row.getComment();
 				if(StringHelper.containsNonWhitespace(comment)) {
-					gtaNode.updatedUserComment(comment, userCourseEnv, getIdentity());
+					courseAssessmentService.updatedUserComment(gtaNode, comment, userCourseEnv, getIdentity());
 				}
 			}
 		}
@@ -594,7 +597,7 @@ public class GroupAssessmentController extends FormBasicController {
 			} else {
 				newScoreEval = new ScoreEvaluation(score, passed, null, userVisible, null, null, null, null);
 			}
-			gtaNode.updateUserScoreEvaluation(newScoreEval, userCourseEnv, getIdentity(), false, Role.coach);
+			courseAssessmentService.updateUserScoreEvaluation(gtaNode, newScoreEval, userCourseEnv, getIdentity(), false, Role.coach);
 		}
 
 		if(withComment) {
@@ -602,7 +605,7 @@ public class GroupAssessmentController extends FormBasicController {
 			if(StringHelper.containsNonWhitespace(comment)) {
 				for(AssessmentRow row:rows) {
 					UserCourseEnvironment userCourseEnv = row.getUserCourseEnvironment(course);
-					gtaNode.updatedUserComment(comment, userCourseEnv, getIdentity());
+					courseAssessmentService.updatedUserComment(gtaNode, comment, userCourseEnv, getIdentity());
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/course/nodes/iq/ConfirmReopenController.java b/src/main/java/org/olat/course/nodes/iq/ConfirmReopenController.java
index 503e6bd47d047ec947afda3ba0473fa91b04fb95..01208a562c49dfe93ac9bcfb46c8f5325e62527c 100644
--- a/src/main/java/org/olat/course/nodes/iq/ConfirmReopenController.java
+++ b/src/main/java/org/olat/course/nodes/iq/ConfirmReopenController.java
@@ -27,6 +27,7 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.nodes.IQTESTCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.course.run.scoring.ScoreEvaluation;
@@ -53,6 +54,8 @@ public class ConfirmReopenController extends FormBasicController {
 	
 	@Autowired
 	private QTI21Service qtiService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	public ConfirmReopenController(UserRequest ureq, WindowControl wControl,
 			CourseEnvironment courseEnv, IQTESTCourseNode courseNode, AssessmentTestSession testSession) {
@@ -86,7 +89,8 @@ public class ConfirmReopenController extends FormBasicController {
 			ScoreEvaluation reopenedScoreEval = new ScoreEvaluation(scoreEval.getScore(), scoreEval.getPassed(),
 					AssessmentEntryStatus.inProgress, scoreEval.getUserVisible(), scoreEval.getFullyAssessed(),
 					scoreEval.getCurrentRunCompletion(), AssessmentRunStatus.running, testSession.getKey());
-			courseNode.updateUserScoreEvaluation(reopenedScoreEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+			courseAssessmentService.updateUserScoreEvaluation(courseNode, reopenedScoreEval, assessedUserCourseEnv,
+					getIdentity(), false, Role.coach);
 
 			ThreadLocalUserActivityLogger.log(QTI21LoggingAction.QTI_REOPEN_IN_COURSE, getClass());
 		}
diff --git a/src/main/java/org/olat/course/nodes/iq/IQIdentityListCourseNodeController.java b/src/main/java/org/olat/course/nodes/iq/IQIdentityListCourseNodeController.java
index fcd383ef66a33ee6c563e5e0ff19b237cf50c304..7a711d78a2e80fc8191426cb49da5f0d24f816b4 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQIdentityListCourseNodeController.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQIdentityListCourseNodeController.java
@@ -51,6 +51,7 @@ import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.Identity;
 import org.olat.course.archiver.ScoreAccountingHelper;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.ui.tool.IdentityListCourseNodeController;
 import org.olat.course.assessment.ui.tool.IdentityListCourseNodeTableModel.IdentityCourseElementCols;
@@ -118,7 +119,8 @@ public class IQIdentityListCourseNodeController extends IdentityListCourseNodeCo
 	private QTI21Service qtiService;
 	@Autowired
 	private BusinessGroupService groupService;
-
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	public IQIdentityListCourseNodeController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
 			RepositoryEntry courseEntry, BusinessGroup group, IQTESTCourseNode courseNode, UserCourseEnvironment coachCourseEnv,
@@ -449,7 +451,8 @@ public class IQIdentityListCourseNodeController extends IdentityListCourseNodeCo
 			ScoreEvaluation manualScoreEval = new ScoreEvaluation(score, passed,
 					finalStatus, scoreEval.getUserVisible(), scoreEval.getFullyAssessed(),
 					scoreEval.getCurrentRunCompletion(), scoreEval.getCurrentRunStatus(), testSession.getKey());
-			((IQTESTCourseNode)courseNode).updateUserScoreEvaluation(manualScoreEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+			courseAssessmentService.updateUserScoreEvaluation(courseNode, manualScoreEval, assessedUserCourseEnv,
+					getIdentity(), false, Role.coach);
 		}
 	}
 	
diff --git a/src/main/java/org/olat/course/nodes/iq/IQPreviewController.java b/src/main/java/org/olat/course/nodes/iq/IQPreviewController.java
index 86f17196d74a24ae5df321fcf7f2f8ba3202b6db..6df77e882ad52653337db82a7ccd8df23b05845c 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQPreviewController.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQPreviewController.java
@@ -31,10 +31,12 @@ 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.gui.control.controller.BasicController;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.nodes.IQTESTCourseNode;
 import org.olat.course.run.scoring.ScoreEvaluation;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.modules.assessment.Role;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Description: <br>
@@ -48,6 +50,9 @@ public class IQPreviewController extends BasicController {
 	private PreviewForm pf;
 	private final UserCourseEnvironment userCourseEnv;
 	private IQTESTCourseNode cn;
+	
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 
 	/**
 	 * @param ureq
@@ -80,7 +85,8 @@ public class IQPreviewController extends BasicController {
 				boolean passed = score >= (cutValue == null ? 0 : cutValue.floatValue());
 				ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), new Boolean(passed));
 				boolean incrementUserAttempts = true;
-				cn.updateUserScoreEvaluation(sceval, userCourseEnv, ureq.getIdentity(), incrementUserAttempts, Role.user);				
+				courseAssessmentService.updateUserScoreEvaluation(cn, sceval, userCourseEnv, ureq.getIdentity(),
+						incrementUserAttempts, Role.user);
 				getWindowControl().setInfo(translate("preview.points.set"));
 			}
 		}
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 9a686c384b22c293b4ba36ce41d16289e228672a..54ac1133abec618c0bcb026d62c400ffb02a5776 100644
--- a/src/main/java/org/olat/course/nodes/iq/IQRunController.java
+++ b/src/main/java/org/olat/course/nodes/iq/IQRunController.java
@@ -71,11 +71,11 @@ 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.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.manager.AssessmentNotificationsHandler;
 import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.highscore.ui.HighScoreRunController;
-import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.IQSELFCourseNode;
 import org.olat.course.nodes.IQSURVCourseNode;
@@ -147,6 +147,9 @@ public class IQRunController extends BasicController implements GenericEventList
 	private AssessmentNotificationsHandler assessmentNotificationsHandler;
 	@Autowired
 	private CourseModule courseModule;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+
 	
 	/**
 	 * Constructor for a test run controller
@@ -535,8 +538,7 @@ public class IQRunController extends BasicController implements GenericEventList
 			}
 			
 			ScoreEvaluation sceval = new ScoreEvaluation(ac.getScore(), ac.isPassed(), assessmentStatus, userVisibility, fullyAssed, null, null, ai.getAssessID());
-			AssessableCourseNode acn = (AssessableCourseNode)courseNode; // assessment nodes are assessable		
-			acn.updateUserScoreEvaluation(sceval, userCourseEnv, getIdentity(), true, Role.user);
+			courseAssessmentService.updateUserScoreEvaluation(courseNode, sceval, userCourseEnv, getIdentity(), true, Role.user);
 				
 			// Mark publisher for notifications
 			Long courseId = userCourseEnv.getCourseEnvironment().getCourseResourceableId();
@@ -671,7 +673,7 @@ public class IQRunController extends BasicController implements GenericEventList
 	    			}
 
 	    			if(assessmentConfig.hasIndividualAsssessmentDocuments()) {
-	    				List<File> docs = acn.getIndividualAssessmentDocuments(userCourseEnv);
+						List<File> docs = courseAssessmentService.getIndividualAssessmentDocuments(acn, userCourseEnv);
 						String mapperUri = registerCacheableMapper(ureq, null, new DocumentsMapper(docs));
 						myContent.contextPut("docsMapperUri", mapperUri);
 						myContent.contextPut("docs", docs);
diff --git a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java
index 3a5c016fb359aac8e1b4ef986cb012050a279693..45680b3444c73ca70878a987a39eafd372152755 100644
--- a/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java
+++ b/src/main/java/org/olat/course/nodes/iq/QTI21AssessmentRunController.java
@@ -61,6 +61,7 @@ import org.olat.course.CourseModule;
 import org.olat.course.DisposedCourseRestartController;
 import org.olat.course.assessment.AssessmentHelper;
 import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.manager.AssessmentNotificationsHandler;
 import org.olat.course.auditing.UserNodeAuditManager;
@@ -146,6 +147,8 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 	@Autowired
 	private CoordinatorManager coordinatorManager;
 	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+	@Autowired
 	private AssessmentNotificationsHandler assessmentNotificationsHandler;
 	
 	public QTI21AssessmentRunController(UserRequest ureq, WindowControl wControl,
@@ -256,7 +259,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 		if (courseNode instanceof SelfAssessableCourseNode) {
 			SelfAssessableCourseNode acn = (SelfAssessableCourseNode)courseNode; 
 			ScoreEvaluation scoreEval = acn.getUserScoreEvaluation(userCourseEnv);
-			Integer attempts = acn.getUserAttempts(userCourseEnv);
+			Integer attempts = acn.getUserAttempts(null, userCourseEnv);
 			if (scoreEval != null) {
 				mainVC.contextPut("resultsVisible", Boolean.TRUE);
 				mainVC.contextPut("hasResults", Boolean.TRUE);
@@ -298,7 +301,8 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 				if(resultsVisible) {
 					AssessmentConfig assessmentConfig = testCourseNode.getAssessmentConfig();
 					if(assessmentConfig.hasComment()) {
-						StringBuilder comment = Formatter.stripTabsAndReturns(testCourseNode.getUserComment(userCourseEnv));
+						StringBuilder comment = Formatter.stripTabsAndReturns(
+								courseAssessmentService.getUserComment(testCourseNode, userCourseEnv));
 						if (comment != null && comment.length() > 0) {
 							mainVC.contextPut("comment", StringHelper.xssScan(comment));
 							mainVC.contextPut("incomment", isPanelOpen(ureq, "comment", true));
@@ -306,7 +310,8 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 					}
 					
 					if(assessmentConfig.hasIndividualAsssessmentDocuments()) {
-						List<File> docs = testCourseNode.getIndividualAssessmentDocuments(userCourseEnv);
+						List<File> docs = courseAssessmentService.getIndividualAssessmentDocuments(testCourseNode,
+								userCourseEnv);
 						String mapperUri = registerCacheableMapper(ureq, null, new DocumentsMapper(docs));
 						mainVC.contextPut("docsMapperUri", mapperUri);
 						mainVC.contextPut("docs", docs);
@@ -749,7 +754,8 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 		
 		removeHistory(ureq);
 		if(courseNode instanceof IQTESTCourseNode) {
-			((IQTESTCourseNode)courseNode).updateCurrentCompletion(userCourseEnv, getIdentity(), null, null, Role.user);
+			courseAssessmentService.updateCurrentCompletion(courseNode, userCourseEnv, getIdentity(), null, null,
+					Role.user);
 		}
 		
 		OLATResourceable ores = OresHelper.createOLATResourceableInstance("test", -1l);
@@ -828,7 +834,8 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 	@Override
 	public void updateOutcomes(Float score, Boolean pass, Double completion) {
 		if(courseNode instanceof IQTESTCourseNode) {
-			((IQTESTCourseNode)courseNode).updateCurrentCompletion(userCourseEnv, getIdentity(), completion, AssessmentRunStatus.running, Role.user);
+			courseAssessmentService.updateCurrentCompletion(courseNode, userCourseEnv, getIdentity(), completion,
+					AssessmentRunStatus.running, Role.user);
 			coordinatorManager.getCoordinator().getEventBus()
 				.fireEventToListenersOf(new CompletionEvent(CompletionEvent.PROGRESS, courseNode.getIdent(), completion, AssessmentRunStatus.running, getIdentity().getKey()),
 						userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseResource());
@@ -856,7 +863,8 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 					completion, AssessmentRunStatus.done, assessmentId);
 			
 			boolean increment = incrementAttempts.getAndSet(false);
-			((IQTESTCourseNode)courseNode).updateUserScoreEvaluation(sceval, userCourseEnv, getIdentity(), increment, Role.user);
+			courseAssessmentService.updateUserScoreEvaluation(courseNode, sceval, userCourseEnv, getIdentity(),
+					increment, Role.user);
 			if(increment) {
 				ThreadLocalUserActivityLogger.log(QTI21LoggingAction.QTI_CLOSE_IN_COURSE, getClass());
 			}
@@ -868,7 +876,7 @@ public class QTI21AssessmentRunController extends BasicController implements Gen
 		} else if(courseNode instanceof SelfAssessableCourseNode) {
 			boolean increment = incrementAttempts.getAndSet(false);
 			if(increment) {
-				((SelfAssessableCourseNode)courseNode).incrementUserAttempts(userCourseEnv, Role.user);
+				((SelfAssessableCourseNode)courseNode).incrementUserAttempts(null, userCourseEnv, Role.user);
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java
index c578d6ae23833285966358a7c0972b8e5aadccf5..84d8942f746bcf68dcbd3b0e30b354821a5d30e4 100644
--- a/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java
+++ b/src/main/java/org/olat/course/nodes/ms/MSCourseNodeRunController.java
@@ -46,6 +46,7 @@ import org.olat.core.util.Util;
 import org.olat.core.util.prefs.Preferences;
 import org.olat.course.CourseModule;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.highscore.ui.HighScoreRunController;
@@ -77,6 +78,8 @@ public class MSCourseNodeRunController extends BasicController implements Activa
 	
 	@Autowired
 	private CourseModule courseModule;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 
 	/**
 	 * Constructor for a manual scoring course run controller
@@ -241,7 +244,8 @@ public class MSCourseNodeRunController extends BasicController implements Activa
 				}
 				
 				if(assessmentConfig.hasIndividualAsssessmentDocuments()) {
-					List<File> docs = courseNode.getIndividualAssessmentDocuments(userCourseEnv);
+					List<File> docs = courseAssessmentService.getIndividualAssessmentDocuments(courseNode,
+							userCourseEnv);
 					mapperUri = registerCacheableMapper(ureq, null, new DocumentsMapper(docs));
 					myContent.contextPut("docsMapperUri", mapperUri);
 					myContent.contextPut("docs", docs);
diff --git a/src/main/java/org/olat/course/nodes/ms/MSResetDataController.java b/src/main/java/org/olat/course/nodes/ms/MSResetDataController.java
index 15ba509662017d460dea02e0a12fe526cd98c3bc..dcc45719b75eff83fd99399b19ce5b35690895a8 100644
--- a/src/main/java/org/olat/course/nodes/ms/MSResetDataController.java
+++ b/src/main/java/org/olat/course/nodes/ms/MSResetDataController.java
@@ -33,6 +33,7 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.id.Roles;
 import org.olat.course.archiver.ScoreAccountingHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.nodes.MSCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -67,6 +68,8 @@ public class MSResetDataController extends FormBasicController {
 	private MSService msService;
 	@Autowired
 	private BusinessGroupService businessGroupService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 
 	public MSResetDataController(UserRequest ureq, WindowControl wControl,
 			CourseEnvironment courseEnv, AssessmentToolOptions asOptions, MSCourseNode courseNode) {
@@ -122,7 +125,8 @@ public class MSResetDataController extends FormBasicController {
 		for(Identity identity:identities) {
 			IdentityEnvironment ienv = new IdentityEnvironment(identity, Roles.userRoles());
 			UserCourseEnvironment uce = new UserCourseEnvironmentImpl(ienv, courseEnv);
-			courseNode.updateUserScoreEvaluation(scoreEval, uce, getIdentity(), false, Role.coach);
+			courseAssessmentService.updateUserScoreEvaluation(courseNode, scoreEval, uce, getIdentity(), false,
+					Role.coach);
 			AuditEnv auditEnv = AuditEnv.of(auditManager, courseNode, identity, getIdentity(), Role.coach);
 			msService.deleteSession(courseEntry, courseNode.getIdent(), identity, auditEnv);
 		}
diff --git a/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeRunController.java
index 05eb30be34804455205aa75f379d2127bd8aa9e2..de93943c8e637c2752f61531e416983f44b188d9 100644
--- a/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeRunController.java
+++ b/src/main/java/org/olat/course/nodes/portfolio/PortfolioCourseNodeRunController.java
@@ -52,6 +52,7 @@ import org.olat.core.util.resource.OresHelper;
 import org.olat.course.CourseModule;
 import org.olat.course.assessment.AssessmentHelper;
 import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.highscore.ui.HighScoreRunController;
 import org.olat.course.nodes.MSCourseNode;
@@ -112,6 +113,8 @@ public class PortfolioCourseNodeRunController extends FormBasicController {
 	private EPFrontendManager ePFMgr;
 	@Autowired
 	private PortfolioService portfolioService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	public PortfolioCourseNodeRunController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv,
 			PortfolioCourseNode courseNode) {
@@ -345,7 +348,7 @@ public class PortfolioCourseNodeRunController extends FormBasicController {
 				}
 				
 				if(assessmentConfig.hasIndividualAsssessmentDocuments()) {
-					List<File> docs = courseNode.getIndividualAssessmentDocuments(userCourseEnv);
+					List<File> docs = courseAssessmentService.getIndividualAssessmentDocuments(courseNode, userCourseEnv);
 					String mapperUri = registerCacheableMapper(ureq, null, new DocumentsMapper(docs));
 					assessmentInfosContainer.contextPut("docsMapperUri", mapperUri);
 					assessmentInfosContainer.contextPut("docs", docs);
diff --git a/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java b/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java
index 93307a3c580083e5247082147a942319912e29b2..3ca6dd516c395023f8edaf4c6d1edf9a4e3554e8 100644
--- a/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java
+++ b/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java
@@ -52,6 +52,7 @@ import org.olat.core.util.UserSession;
 import org.olat.core.util.Util;
 import org.olat.core.util.event.GenericEventListener;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.editor.NodeEditController;
 import org.olat.course.highscore.ui.HighScoreRunController;
@@ -105,6 +106,8 @@ public class ScormRunController extends BasicController implements ScormAPICallb
 	
 	@Autowired
 	private ScormMainManager scormMainManager;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 
 	/**
 	 * Use this constructor to launch a CP via Repository reference key set in
@@ -178,7 +181,7 @@ public class ScormRunController extends BasicController implements ScormAPICallb
 		int maxAttempts = config.getIntegerSafe(ScormEditController.CONFIG_MAXATTEMPTS, 0);
 		boolean maxAttemptsReached = false;
 		if (maxAttempts > 0) {
-			if (scormNode.getUserAttempts(userCourseEnv) >= maxAttempts) {
+			if (courseAssessmentService.getUserAttempts(scormNode, userCourseEnv) >= maxAttempts) {
 				maxAttemptsReached = true;
 			}
 		}
@@ -246,10 +249,11 @@ public class ScormRunController extends BasicController implements ScormAPICallb
 			startPage.contextPut("resultsVisible", resultsVisible);
 			AssessmentConfig assessmentConfig = scormNode.getAssessmentConfig();
 			if(resultsVisible && assessmentConfig.hasComment()) {
-				StringBuilder comment = Formatter.stripTabsAndReturns(scormNode.getUserComment(userCourseEnv));
+				StringBuilder comment = Formatter
+						.stripTabsAndReturns(courseAssessmentService.getUserComment(scormNode, userCourseEnv));
 				startPage.contextPut("comment", StringHelper.xssScan(comment));
 			}
-			startPage.contextPut("attempts", scormNode.getUserAttempts(userCourseEnv));
+			startPage.contextPut("attempts", courseAssessmentService.getUserAttempts(scormNode, userCourseEnv));
 			
 			if(ureq == null) {// High score need one
 				ureq = new SyntheticUserRequest(getIdentity(), getLocale(), userSession);
@@ -313,7 +317,7 @@ public class ScormRunController extends BasicController implements ScormAPICallb
 			//increment user attempts only once!
 			if(!config.getBooleanSafe(ScormEditController.CONFIG_ADVANCESCORE, true)
 					|| !config.getBooleanSafe(ScormEditController.CONFIG_ATTEMPTSDEPENDONSCORE, false)) {
-				scormNode.incrementUserAttempts(userCourseEnv, Role.user);
+				courseAssessmentService.incrementUserAttempts(scormNode, userCourseEnv, Role.user);
 				attemptsIncremented = true;
 			}
 			
diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxController.java b/src/main/java/org/olat/course/nodes/ta/DropboxController.java
index feb85ce4265ea447c12627f5276a1a0b57abe0cf..747450add4f919e4ab051c2dc171ad5eb6ac87e4 100644
--- a/src/main/java/org/olat/course/nodes/ta/DropboxController.java
+++ b/src/main/java/org/olat/course/nodes/ta/DropboxController.java
@@ -77,8 +77,8 @@ import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.callbacks.FullAccessWithQuotaCallback;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.auditing.UserNodeAuditManager;
-import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.TACourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -112,6 +112,8 @@ public class DropboxController extends BasicController {
 	private QuotaManager quotaManager;
 	@Autowired
 	private VFSRepositoryService vfsRepositoryService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	// Constructor for ProjectBrokerDropboxController
 	protected DropboxController(UserRequest ureq, WindowControl wControl) {
@@ -201,6 +203,7 @@ public class DropboxController extends BasicController {
 	/**
 	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
 	 */
+	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if (source == ulButton) {
 			
@@ -360,8 +363,7 @@ public class DropboxController extends BasicController {
 		c.put("time", f.formatTime(now));
 		
 		// update attempts counter for this user: one file - one attempts
-		AssessableCourseNode acn = (AssessableCourseNode) node;
-		acn.incrementUserAttempts(userCourseEnv, Role.user);
+		courseAssessmentService.incrementUserAttempts(node, userCourseEnv, Role.user);
 				
 		// log entry for this file
 		UserNodeAuditManager am = userCourseEnv.getCourseEnvironment().getAuditManager();
diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
index 10000ac9bcfa2ed1c92b4a643e944eb81e435eb9..018fb41a579fc499cd98b7b3b2f18f0a2bf5ef6f 100644
--- a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
+++ b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
@@ -72,6 +72,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.core.util.vfs.callbacks.ReadOnlyCallback;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.auditing.UserNodeAuditManager;
 import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.nodes.CourseNode;
@@ -112,6 +113,8 @@ public class DropboxScoringViewController extends BasicController {
 	
 	@Autowired
 	private QuotaManager quotaManager;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	/**
 	 * Scoring view of the dropbox.
@@ -305,7 +308,7 @@ public class DropboxScoringViewController extends BasicController {
 						AssessmentEvaluation eval = acn.getUserScoreEvaluation(userCourseEnv);
 						if(eval.getAssessmentStatus() == null || eval.getAssessmentStatus() == AssessmentEntryStatus.notStarted) {
 							eval = new AssessmentEvaluation(eval, AssessmentEntryStatus.inProgress);
-							acn.updateUserScoreEvaluation(eval, userCourseEnv, coach, false, Role.coach);
+							courseAssessmentService.updateUserScoreEvaluation(acn, eval, userCourseEnv, coach, false, Role.coach);
 						}
 					}
 
@@ -344,7 +347,7 @@ public class DropboxScoringViewController extends BasicController {
 					}
 					if(eval.getAssessmentStatus() == null || eval.getAssessmentStatus() == AssessmentEntryStatus.notStarted) {
 						eval = new AssessmentEvaluation(eval, AssessmentEntryStatus.inProgress);
-						acn.updateUserScoreEvaluation(eval, userCourseEnv, getIdentity(), false, Role.coach);
+						courseAssessmentService.updateUserScoreEvaluation(acn, eval, userCourseEnv, getIdentity(), false, Role.coach);
 						fireEvent(ureq, Event.CHANGED_EVENT);
 					}
 				}
diff --git a/src/main/java/org/olat/ims/qti/QTI12ResultDetailsController.java b/src/main/java/org/olat/ims/qti/QTI12ResultDetailsController.java
index 2b6542d149ebfb3a3371d709b721834ecf997886..4ab50cebeafc9416a6c67ca66ecdccf04a745d93 100644
--- a/src/main/java/org/olat/ims/qti/QTI12ResultDetailsController.java
+++ b/src/main/java/org/olat/ims/qti/QTI12ResultDetailsController.java
@@ -50,6 +50,7 @@ import org.olat.core.util.i18n.I18nModule;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.OpenSubDetailsEvent;
 import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.run.scoring.ScoreEvaluation;
@@ -70,6 +71,7 @@ import org.olat.modules.iq.IQManager;
 import org.olat.modules.iq.IQRetrievedEvent;
 import org.olat.repository.RepositoryEntry;
 import org.olat.user.UserManager;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Initial Date:  12.01.2005
@@ -95,6 +97,9 @@ public class QTI12ResultDetailsController extends BasicController {
 	private DialogBoxController retrieveConfirmationCtr;
 	private QTI12XSLTResultDetailsController xsltDetailsCtr;
 	
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+	
 	/**
 	 * @param courseResourceableId
 	 * @param nodeIdent
@@ -263,7 +268,7 @@ public class QTI12ResultDetailsController extends BasicController {
 		Boolean passed = Boolean.valueOf(ac.isPassed());
 		ScoreEvaluation sceval = new ScoreEvaluation(score, passed, Boolean.FALSE, new Long(ai.getAssessID()));
 		UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
-		testNode.updateUserScoreEvaluation(sceval, userCourseEnv, assessedIdentity, true, Role.coach);
+		courseAssessmentService.updateUserScoreEvaluation(testNode, sceval, userCourseEnv, assessedIdentity, true, Role.coach);
 		
 		//cleanup
 		ai.cleanUp();
diff --git a/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java b/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java
index 6f2f417aacd1b331d17c3eb1fcc8e39b23c52582..99b1c0449832ab44e8265c82ef31dcb6038a4d7f 100644
--- a/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java
+++ b/src/main/java/org/olat/ims/qti/statistics/ui/QTI12PullTestsToolController.java
@@ -40,6 +40,7 @@ import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.archiver.ScoreAccountingHelper;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.nodes.IQTESTCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.course.run.scoring.ScoreEvaluation;
@@ -77,6 +78,8 @@ public class QTI12PullTestsToolController extends FormBasicController {
 	private UserManager userManager;
 	@Autowired
 	private BusinessGroupService businessGroupService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	public QTI12PullTestsToolController(UserRequest ureq, WindowControl wControl, CourseEnvironment courseEnv,
 			AssessmentToolOptions asOptions, IQTESTCourseNode courseNode) {
@@ -184,7 +187,8 @@ public class QTI12PullTestsToolController extends FormBasicController {
 		Boolean passed = new Boolean(ac.isPassed());
 		ScoreEvaluation sceval = new ScoreEvaluation(score, passed, Boolean.FALSE, new Long(ai.getAssessID()));
 		UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
-		courseNode.updateUserScoreEvaluation(sceval, userCourseEnv, assessedIdentity, true, Role.coach);
+		courseAssessmentService.updateUserScoreEvaluation(courseNode, sceval, userCourseEnv, assessedIdentity, true,
+				Role.coach);
 		
 		//cleanup
 		ai.cleanUp();
diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java
index ccd6d30e718a4d3557c500a36e7e3dde6efd8d41..515fcda13070f2eb20334e626b4b607c6c2e255c 100644
--- a/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/QTI21AssessmentDetailsController.java
@@ -67,6 +67,7 @@ import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.Identity;
 import org.olat.core.util.StringHelper;
 import org.olat.course.CourseFactory;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.nodes.IQTESTCourseNode;
 import org.olat.course.nodes.iq.IQEditController;
 import org.olat.course.nodes.iq.QTI21AssessmentRunController;
@@ -156,6 +157,8 @@ public class QTI21AssessmentDetailsController extends FormBasicController {
 	private RepositoryManager repositoryManager;
 	@Autowired
 	private AssessmentService assessmentService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	/**
 	 * The constructor used by the assessment tool of the course.
@@ -441,7 +444,8 @@ public class QTI21AssessmentDetailsController extends FormBasicController {
 		ScoreEvaluation manualScoreEval = new ScoreEvaluation(score, passed,
 				finalStatus, null, scoreEval.getFullyAssessed(), 
 				scoreEval.getCurrentRunCompletion(), scoreEval.getCurrentRunStatus(), session.getKey());
-		courseNode.updateUserScoreEvaluation(manualScoreEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+		courseAssessmentService.updateUserScoreEvaluation(courseNode, manualScoreEval, assessedUserCourseEnv,
+				getIdentity(), false, Role.coach);
 	}
 	
 	private void doUpdateEntry(AssessmentTestSession session) {
diff --git a/src/main/java/org/olat/ims/qti21/ui/QTI21ResetDataController.java b/src/main/java/org/olat/ims/qti21/ui/QTI21ResetDataController.java
index 8ae669e7c6a609b966c0ef50a2be10ebc99a93c8..30178d4b3b34ef670d9254d8214bc3ac8f2f7bbe 100644
--- a/src/main/java/org/olat/ims/qti21/ui/QTI21ResetDataController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/QTI21ResetDataController.java
@@ -47,6 +47,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.archiver.ScoreAccountingHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.nodes.ArchiveOptions;
 import org.olat.course.nodes.IQTESTCourseNode;
 import org.olat.course.nodes.QTICourseNode;
@@ -92,6 +93,8 @@ public class QTI21ResetDataController extends FormBasicController {
 	private BusinessGroupService businessGroupService;
 	@Autowired
 	private RepositoryService repositoryService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 
 	public QTI21ResetDataController(UserRequest ureq, WindowControl wControl, 
 			CourseEnvironment courseEnv, AssessmentToolOptions asOptions, QTICourseNode courseNode) {
@@ -195,7 +198,6 @@ public class QTI21ResetDataController extends FormBasicController {
 	@Override
 	protected void formOK(UserRequest ureq) {
 		if(courseNode instanceof IQTESTCourseNode) {
-			IQTESTCourseNode testCourseNode = (IQTESTCourseNode)courseNode;
 			RepositoryEntry testEntry = courseNode.getReferencedRepositoryEntry();
 			RepositoryEntry courseEntry = courseEnv.getCourseGroupManager().getCourseEntry();
 			
@@ -207,8 +209,10 @@ public class QTI21ResetDataController extends FormBasicController {
 				ScoreEvaluation scoreEval = new ScoreEvaluation(null, null, AssessmentEntryStatus.notStarted, null, Boolean.FALSE, 0.0d, AssessmentRunStatus.notStarted, null);
 				IdentityEnvironment ienv = new IdentityEnvironment(identity, Roles.userRoles());
 				UserCourseEnvironment uce = new UserCourseEnvironmentImpl(ienv, courseEnv);
-				testCourseNode.updateUserScoreEvaluation(scoreEval, uce, getIdentity(), false, Role.coach);
-				testCourseNode.updateCurrentCompletion(uce, getIdentity(), null, AssessmentRunStatus.notStarted, Role.coach);
+				courseAssessmentService.updateUserScoreEvaluation(courseNode, scoreEval, uce, getIdentity(), false,
+						Role.coach);
+				courseAssessmentService.updateCurrentCompletion(courseNode, uce, getIdentity(), null,
+						AssessmentRunStatus.notStarted, Role.coach);
 			}
 		} else if(assessedEntry != null) {
 			archiveData(assessedEntry);
diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityAssessmentItemController.java b/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityAssessmentItemController.java
index 57aec451872d20ae4a7116bc52c91c64057ac3d7..1f3c797821afe42a909a8596bfbb16a154ce890f 100644
--- a/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityAssessmentItemController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/assessment/CorrectionIdentityAssessmentItemController.java
@@ -40,6 +40,7 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.util.StringHelper;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.nodes.IQTESTCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.course.run.scoring.ScoreEvaluation;
@@ -92,6 +93,8 @@ public class CorrectionIdentityAssessmentItemController extends FormBasicControl
 
 	@Autowired
 	private QTI21Service qtiService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
 	
 	public CorrectionIdentityAssessmentItemController(UserRequest ureq, WindowControl wControl,
 			RepositoryEntry testEntry, ResolvedAssessmentTest resolvedAssessmentTest,
@@ -252,6 +255,7 @@ public class CorrectionIdentityAssessmentItemController extends FormBasicControl
 		ScoreEvaluation manualScoreEval = new ScoreEvaluation(score, passed,
 				scoreEval.getAssessmentStatus(), scoreEval.getUserVisible(), scoreEval.getFullyAssessed(),
 				scoreEval.getCurrentRunCompletion(), scoreEval.getCurrentRunStatus(), testSession.getKey());
-		courseNode.updateUserScoreEvaluation(manualScoreEval, assessedUserCourseEnv, getIdentity(), false, Role.coach);
+		courseAssessmentService.updateUserScoreEvaluation(courseNode, manualScoreEval, assessedUserCourseEnv,
+				getIdentity(), false, Role.coach);
 	}
 }
diff --git a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java
index 826483dd527c5bc7c01eb61df83d4e00bdec14e6..858951169585e814bcec52b92ed7401a3b31f472 100644
--- a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java
+++ b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java
@@ -54,6 +54,7 @@ import org.olat.core.util.xml.XStreamHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.PortfolioCourseNode;
 import org.olat.course.run.scoring.AssessmentEvaluation;
@@ -180,6 +181,9 @@ public class PortfolioServiceImpl implements PortfolioService {
 	private AssessmentSectionDAO assessmentSectionDao;
 	@Autowired
 	private AssessmentService assessmentService;
+	@Autowired
+	private CourseAssessmentService courseAssessmentService;
+
 	@Autowired
 	private RepositoryService repositoryService;
 	@Autowired
@@ -1298,7 +1302,7 @@ public class PortfolioServiceImpl implements PortfolioService {
 				PortfolioCourseNode pfNode = (PortfolioCourseNode)courseNode;
 				for(Identity assessedIdentity:assessedIdentities) {
 					UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
-					pfNode.updateLastModifications(userCourseEnv, doer, by);
+					courseAssessmentService.updateLastModifications(pfNode, userCourseEnv, doer, by);
 				}
 			}
 		} else {
@@ -1408,10 +1412,10 @@ public class PortfolioServiceImpl implements PortfolioService {
 			ICourse course = CourseFactory.loadCourse(entry);
 			CourseNode courseNode = course.getRunStructure().getNode(binder.getSubIdent());
 			if(courseNode instanceof PortfolioCourseNode) {
-				PortfolioCourseNode pfNode = (PortfolioCourseNode)courseNode;
 				ScoreEvaluation scoreEval= new ScoreEvaluation(totalScore.floatValue(), totalPassed, binderStatus, true, true, null, null, binder.getKey());
 				UserCourseEnvironment userCourseEnv = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course);
-				pfNode.updateUserScoreEvaluation(scoreEval, userCourseEnv, coachingIdentity, false, Role.coach);
+				courseAssessmentService.updateUserScoreEvaluation(courseNode, scoreEval, userCourseEnv,
+						coachingIdentity, false, Role.coach);
 			}
 		} else {
 			OLATResource resource = ((BinderImpl)binder.getTemplate()).getOlatResource();
@@ -1467,7 +1471,8 @@ public class PortfolioServiceImpl implements PortfolioService {
 				AssessmentEvaluation eval = pfNode.getUserScoreEvaluation(userCourseEnv);
 				
 				ScoreEvaluation scoreEval= new ScoreEvaluation(eval.getScore(), eval.getPassed(), status, true, fullyAssessed, null, null, binder.getKey());
-				pfNode.updateUserScoreEvaluation(scoreEval, userCourseEnv, coachingIdentity, false, Role.coach);
+				courseAssessmentService.updateUserScoreEvaluation(courseNode, scoreEval, userCourseEnv,
+						coachingIdentity, false, Role.coach);
 			}
 		} else {
 			OLATResource resource = ((BinderImpl)binder.getTemplate()).getOlatResource();
diff --git a/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java b/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java
index 0c7d2eba77c5395d25128de51a8b1a3599605cb7..72476f77aee53d542a61adeebc2ea97c80805928 100644
--- a/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java
+++ b/src/main/java/org/olat/modules/scorm/ScormAPIMapper.java
@@ -49,6 +49,7 @@ import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.assessment.handler.AssessmentConfig;
 import org.olat.course.assessment.manager.AssessmentNotificationsHandler;
 import org.olat.course.nodes.ScormCourseNode;
@@ -197,20 +198,23 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable {
 		boolean passed = (found == scormAdapter.getNumOfSCOs()) && passedScos;
 		// if advanceScore option is set update the score only if it is higher
 		// <OLATEE-27>
+		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 		ModuleConfiguration config = scormNode.getModuleConfiguration();
 		if (config.getBooleanSafe(ScormEditController.CONFIG_ADVANCESCORE, true)) {
 			if (currentPassed == null || !currentPassed.booleanValue()) {
 				// </OLATEE-27>
 				boolean increment = !attemptsIncremented && finish;
 				ScoreEvaluation sceval = new ScoreEvaluation(Float.valueOf(0.0f), Boolean.valueOf(passed));
-				scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment, Role.user);
+				courseAssessmentService.updateUserScoreEvaluation(scormNode, sceval, userCourseEnv, identity, increment,
+						Role.user);
 				if(increment) {
 					attemptsIncremented = true;
 				}
 			} else if (!config.getBooleanSafe(ScormEditController.CONFIG_ATTEMPTSDEPENDONSCORE, false)) {
 				boolean increment = !attemptsIncremented && finish;
 				ScoreEvaluation sceval = scormNode.getUserScoreEvaluation(userCourseEnv);
-				scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment, Role.user);
+				courseAssessmentService.updateUserScoreEvaluation(scormNode, sceval, userCourseEnv, identity, increment,
+						Role.user);
 				if(increment) {
 					attemptsIncremented = true;
 				}
@@ -218,7 +222,8 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable {
 		} else {
 			boolean increment = !attemptsIncremented && finish;
 			ScoreEvaluation sceval = new ScoreEvaluation(Float.valueOf(0.0f), Boolean.valueOf(passed));
-			scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, false, Role.user);
+			courseAssessmentService.updateUserScoreEvaluation(scormNode, sceval, userCourseEnv, identity, false,
+					Role.user);
 			if(increment) {
 				attemptsIncremented = true;
 			}
@@ -258,20 +263,23 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable {
 		boolean passed = (score >= cutval);
 		// if advanceScore option is set update the score only if it is higher
 		// <OLATEE-27>
+		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 		ModuleConfiguration config = scormNode.getModuleConfiguration();
 		if (config.getBooleanSafe(ScormEditController.CONFIG_ADVANCESCORE, true)) {
 			if (score > (currentScore != null ? currentScore : -1f)) {
 				// </OLATEE-27>
 				boolean increment = !attemptsIncremented && finish;
 				ScoreEvaluation sceval = new ScoreEvaluation(Float.valueOf(score), Boolean.valueOf(passed));
-				scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment, Role.user);
+				courseAssessmentService.updateUserScoreEvaluation(scormNode, sceval, userCourseEnv, identity, increment,
+						Role.user);
 				if(increment) {
 					attemptsIncremented = true;
 				}
 			} else if (!config.getBooleanSafe(ScormEditController.CONFIG_ATTEMPTSDEPENDONSCORE, false)) {
 				boolean increment = !attemptsIncremented && finish;
 				ScoreEvaluation sceval = scormNode.getUserScoreEvaluation(userCourseEnv);
-				scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, increment, Role.user);
+				courseAssessmentService.updateUserScoreEvaluation(scormNode, sceval, userCourseEnv, identity, increment,
+						Role.user);
 				if(increment) {
 					attemptsIncremented = true;
 				}
@@ -284,7 +292,7 @@ public class ScormAPIMapper implements Mapper, ScormAPICallback, Serializable {
 			// </OLATEE-27>
 			boolean increment = !attemptsIncremented && finish;
 			ScoreEvaluation sceval = new ScoreEvaluation(Float.valueOf(score), Boolean.valueOf(passed));
-			scormNode.updateUserScoreEvaluation(sceval, userCourseEnv, identity, false, Role.user);
+			courseAssessmentService.updateUserScoreEvaluation(scormNode, sceval, userCourseEnv, identity, false, Role.user);
 			if(increment) {
 				attemptsIncremented = true;
 			}
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 eca87b92539ab7a5a1a86aa661980e66dad60860..3844bee3ce8bd7374fa64ef6dca7c35297e06abb 100644
--- a/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CourseAssessmentWebService.java
@@ -48,12 +48,14 @@ import org.apache.logging.log4j.Logger;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.basesecurity.OrganisationRoles;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.logging.Tracing;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentManager;
+import org.olat.course.assessment.CourseAssessmentService;
 import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.groupsandrights.CourseRights;
 import org.olat.course.nodes.AssessableCourseNode;
@@ -331,9 +333,9 @@ public class CourseAssessmentWebService {
 		if (node instanceof IQTESTCourseNode) {
 			importTestItems(course, nodeKey, requestIdentity, resultsVO);
 		} else {
-			AssessableCourseNode assessableNode = (AssessableCourseNode) node;
+			CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 			ScoreEvaluation scoreEval = new ScoreEvaluation(resultsVO.getScore(), Boolean.TRUE, Boolean.TRUE, Long.valueOf(nodeKey));//not directly pass this key
-			assessableNode.updateUserScoreEvaluation(scoreEval, userCourseEnvironment, requestIdentity, true, Role.coach);
+			courseAssessmentService.updateUserScoreEvaluation(node, scoreEval, userCourseEnvironment, requestIdentity, true, Role.coach);
 		}
 
 		CourseFactory.saveCourseEditorTreeModel(course.getResourceableId());
@@ -424,7 +426,8 @@ public class CourseAssessmentWebService {
 				AssessableCourseNode acn = (AssessableCourseNode) courseNode;
 				// assessment nodes are assessable
 				boolean incrementUserAttempts = true;
-				acn.updateUserScoreEvaluation(sceval, userCourseEnv, identity, incrementUserAttempts, Role.coach);
+				CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
+				courseAssessmentService.updateUserScoreEvaluation(acn, sceval, userCourseEnv, identity, incrementUserAttempts, Role.coach);
 			} else {
 				log.error("Result set already saved");
 			}