diff --git a/src/main/java/org/olat/modules/fo/manager/ForumManager.java b/src/main/java/org/olat/modules/fo/manager/ForumManager.java
index 744bbd0e2b88466a4979f95b068bba55a4097cd7..0b1cd251ecdd747031011c2b3b060f13b703f4cf 100644
--- a/src/main/java/org/olat/modules/fo/manager/ForumManager.java
+++ b/src/main/java/org/olat/modules/fo/manager/ForumManager.java
@@ -25,6 +25,7 @@
 
 package org.olat.modules.fo.manager;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
@@ -39,6 +40,7 @@ import javax.persistence.TemporalType;
 import javax.persistence.TypedQuery;
 
 import org.olat.basesecurity.IdentityRef;
+import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.services.mark.MarkingService;
@@ -809,6 +811,15 @@ public class ForumManager {
 		return null;
 	}
 	
+	public File getMessageDirectory(Long forumKey, Long messageKey, boolean create) {
+		File forumDir = getForumDirectory(forumKey);
+		File messageDir = new File(forumDir, messageKey.toString());
+		if(create && !messageDir.exists()) {
+			messageDir.mkdirs();
+		}
+		return messageDir;
+	}
+	
 	private void moveMessageContainer(Long fromForumKey, Long fromMessageKey, Long toForumKey, Long toMessageKey) {
 		// copy message container
 		VFSContainer toMessageContainer = getMessageContainer(toForumKey, toMessageKey);
@@ -840,6 +851,15 @@ public class ForumManager {
 		return null;
 	}
 	
+	public File getForumDirectory(Long forumKey) {
+		File forumsDir = new File(FolderConfig.getCanonicalRoot(), "forum");
+		File forumDir = new File(forumsDir,forumKey.toString());
+		if(!forumDir.exists()) {
+			forumDir.mkdirs();
+		}
+		return forumDir;
+	}
+	
 	/**
 	 * Splits the current thread starting from the current message.
 	 * It updates the messages of the selected subthread by setting the Parent and the Threadtop.
diff --git a/src/main/java/org/olat/modules/fo/portfolio/ForumMediaHandler.java b/src/main/java/org/olat/modules/fo/portfolio/ForumMediaHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f075e510ff1da21060ec7ab443583424f1cd5dd
--- /dev/null
+++ b/src/main/java/org/olat/modules/fo/portfolio/ForumMediaHandler.java
@@ -0,0 +1,103 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.fo.portfolio;
+
+import java.io.File;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.core.util.FileUtils;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.modules.fo.Forum;
+import org.olat.modules.fo.Message;
+import org.olat.modules.fo.MessageLight;
+import org.olat.modules.fo.manager.ForumManager;
+import org.olat.modules.portfolio.Media;
+import org.olat.modules.portfolio.handler.AbstractMediaHandler;
+import org.olat.modules.portfolio.manager.MediaDAO;
+import org.olat.modules.portfolio.manager.PortfolioFileStorage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 20.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class ForumMediaHandler extends AbstractMediaHandler {
+	
+	public static final String FORUM_HANDLER = OresHelper.calculateTypeName(Forum.class);
+	
+	@Autowired
+	private MediaDAO mediaDao;
+	@Autowired
+	private ForumManager forumManager;
+	@Autowired
+	private PortfolioFileStorage fileStorage;
+	
+	public ForumMediaHandler() {
+		super(FORUM_HANDLER);
+	}
+
+	@Override
+	public String getIconCssClass() {
+		return "o_fo_icon";
+	}
+
+	@Override
+	public Media createMedia(String title, String description, Object mediaObject, String businessPath, Identity author) {
+		Message message = null;
+		if(mediaObject instanceof Message) {
+			message = (Message)mediaObject;
+		} else if(mediaObject instanceof MessageLight) {
+			MessageLight messageLight = (MessageLight)mediaObject;
+			message = forumManager.loadMessage(messageLight.getKey());
+		}
+		
+		String content = message.getBody();
+		Media media = mediaDao.createMedia(title, description, content, FORUM_HANDLER, businessPath, 70, author);
+		
+		File messageDir = forumManager.getMessageDirectory(message.getForum().getKey(), message.getKey(), false);
+		if (messageDir != null && messageDir.exists()) {
+			File[] attachments = messageDir.listFiles();
+			if (attachments.length > 0) {
+				File mediaDir = fileStorage.generateMediaSubDirectory(media);
+				for(File attachment:attachments) {
+					FileUtils.copyFileToDir(attachment, mediaDir, "Forum media");
+				}
+				String storagePath = fileStorage.getRelativePath(mediaDir);
+				media = mediaDao.updateStoragePath(media, storagePath);
+			}
+		}
+
+		return media;
+	}
+
+	@Override
+	public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media) {
+		return new ForumMessageMediaController(ureq, wControl, media);
+	}
+	
+	
+}
diff --git a/src/main/java/org/olat/modules/fo/portfolio/ForumMessageMediaController.java b/src/main/java/org/olat/modules/fo/portfolio/ForumMessageMediaController.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd04f4135b0826f23c0dae08398c7d4ee6ef7a3c
--- /dev/null
+++ b/src/main/java/org/olat/modules/fo/portfolio/ForumMessageMediaController.java
@@ -0,0 +1,84 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.fo.portfolio;
+
+import java.util.List;
+
+import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.download.DownloadComponent;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+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.core.gui.util.CSSHelper;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.restapi.SystemItemFilter;
+import org.olat.modules.portfolio.Media;
+
+/**
+ * 
+ * Initial date: 20.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ForumMessageMediaController extends BasicController {
+
+	public ForumMessageMediaController(UserRequest ureq, WindowControl wControl, Media media) {
+		super(ureq, wControl);
+
+		VelocityContainer mainVC = createVelocityContainer("messageDetails");
+		mainVC.contextPut("text", media.getContent());
+		if (StringHelper.containsNonWhitespace(media.getStoragePath())) {
+			VFSContainer attachmentsContainer = new OlatRootFolderImpl("/" + media.getStoragePath(), null);
+			List<VFSItem> attachments = attachmentsContainer.getItems(new SystemItemFilter());
+			int i=1; //vc-shift!
+			for (VFSItem attachment : attachments) {
+				if(attachment instanceof VFSLeaf) {
+					VFSLeaf file = (VFSLeaf)attachment;
+					DownloadComponent downlC = new DownloadComponent("download"+i, file, true,
+							file.getName() + " (" + String.valueOf(file.getSize() / 1024) + " KB)", null,
+							CSSHelper.createFiletypeIconCssClassFor(file.getName()));
+					mainVC.put("download"+i, downlC);
+					i++;
+				}
+			}
+			mainVC.contextPut("attachments", attachments);
+			mainVC.contextPut("hasAttachments", true);
+		} 
+		
+		putInitialPanel(mainVC);		
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		//
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+}
+
diff --git a/src/main/java/org/olat/modules/fo/ui/MessageListController.java b/src/main/java/org/olat/modules/fo/ui/MessageListController.java
index 2cfddeb97745336b85a84bd51d2f972af91b5595..ed415bc9125dedcd05b9312c082e1d0ac4469eb2 100644
--- a/src/main/java/org/olat/modules/fo/ui/MessageListController.java
+++ b/src/main/java/org/olat/modules/fo/ui/MessageListController.java
@@ -84,11 +84,14 @@ import org.olat.modules.fo.MessageRef;
 import org.olat.modules.fo.Status;
 import org.olat.modules.fo.archiver.formatters.ForumDownloadResource;
 import org.olat.modules.fo.manager.ForumManager;
+import org.olat.modules.fo.portfolio.ForumMediaHandler;
 import org.olat.modules.fo.ui.MessageEditController.EditMode;
 import org.olat.modules.fo.ui.events.DeleteMessageEvent;
 import org.olat.modules.fo.ui.events.DeleteThreadEvent;
 import org.olat.modules.fo.ui.events.ErrorEditMessage;
 import org.olat.modules.fo.ui.events.SelectMessageEvent;
+import org.olat.modules.portfolio.PortfolioV2Module;
+import org.olat.modules.portfolio.ui.component.MediaCollectorComponent;
 import org.olat.portfolio.EPUIFactory;
 import org.olat.portfolio.manager.EPFrontendManager;
 import org.olat.user.DisplayPortraitController;
@@ -153,6 +156,10 @@ public class MessageListController extends BasicController implements GenericEve
 	private BaseSecurityModule securityModule;
 	@Autowired
 	private EPFrontendManager epMgr;
+	@Autowired
+	private PortfolioV2Module portfolioModule;
+	@Autowired
+	private ForumMediaHandler forumMediaHandler;
 	
 	public MessageListController(UserRequest ureq, WindowControl wControl,
 			Forum forum, ForumCallback foCallback) {
@@ -673,11 +680,17 @@ public class MessageListController extends BasicController implements GenericEve
 					+ "[Message:" + m.getKey() + "]";
 			Long artefact = artefactStats.get(businessPath);
 			int numOfArtefact = artefact == null ? 0 : artefact.intValue();
-			Controller ePFCollCtrl = EPUIFactory
-					.createArtefactCollectWizzardController(ureq, getWindowControl(), numOfArtefact, messageOres, businessPath);
-			if (ePFCollCtrl != null) {
-				messageView.setArtefact(ePFCollCtrl);
-				mainVC.put("eportfolio_" + keyString, ePFCollCtrl.getInitialComponent());
+			if(portfolioModule.isEnabled()) {
+				String collectorId = "eportfolio_" + keyString;
+				Component collectorCmp = new MediaCollectorComponent(collectorId, getWindowControl(), m, forumMediaHandler, businessPath);
+				mainVC.put(collectorId, collectorCmp);
+			} else  {
+				Controller ePFCollCtrl = EPUIFactory
+						.createArtefactCollectWizzardController(ureq, getWindowControl(), numOfArtefact, messageOres, businessPath);
+				if (ePFCollCtrl != null) {
+					messageView.setArtefact(ePFCollCtrl);
+					mainVC.put("eportfolio_" + keyString, ePFCollCtrl.getInitialComponent());
+				}
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/modules/portfolio/Media.java b/src/main/java/org/olat/modules/portfolio/Media.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9150061d9b944cb23bfc084842b56922887fe96
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/Media.java
@@ -0,0 +1,54 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio;
+
+import java.util.Date;
+
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 17.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface Media {
+	
+	public Long getKey();
+	
+	public Date getCreationDate();
+	
+	public Date getCollectionDate();
+	
+	public String getStoragePath();
+	
+	public String getType();
+	
+	public String getTitle();
+	
+	public String getDescription();
+	
+	public String getContent();
+	
+	public String getBusinessPath();
+	
+	public Identity getAuthor();
+
+}
diff --git a/src/main/java/org/olat/modules/portfolio/MediaHandler.java b/src/main/java/org/olat/modules/portfolio/MediaHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..8b0ccc0f4fc39c5e8b6aea49a6dddc269491df18
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/MediaHandler.java
@@ -0,0 +1,43 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+
+/**
+ * 
+ * Initial date: 20.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface MediaHandler {
+	
+	public String getType();
+	
+	public String getIconCssClass();
+	
+	public Media createMedia(String title, String description, Object mediaObject, String businessPath, Identity author);
+	
+	public Controller getMediaController(UserRequest ureq, WindowControl wControl, Media media);
+
+}
diff --git a/src/main/java/org/olat/modules/portfolio/PortfolioService.java b/src/main/java/org/olat/modules/portfolio/PortfolioService.java
index 905fbbe86f5b7c7b670049e5d18785bb34f12ad7..3c3c0f27cf0ee816e452c3556a76ae0f72ec9283 100644
--- a/src/main/java/org/olat/modules/portfolio/PortfolioService.java
+++ b/src/main/java/org/olat/modules/portfolio/PortfolioService.java
@@ -100,7 +100,14 @@ public interface PortfolioService {
 	
 	public List<Binder> getBinders(Identity owner, RepositoryEntryRef courseEntry, String subIdent);
 	
-	public boolean isTemplateInUse(Binder binder, RepositoryEntry courseEntry, String subIdent);
+	/**
+	 * Check if this template is used, has some copies.
+	 * @param template
+	 * @param courseEntry
+	 * @param subIdent
+	 * @return
+	 */
+	public boolean isTemplateInUse(Binder template, RepositoryEntry courseEntry, String subIdent);
 	
 	public Binder assignBinder(Identity owner, BinderRef templateBinder, RepositoryEntry courseEntry, String subIdent, Date deadline);
 	
@@ -200,5 +207,14 @@ public interface PortfolioService {
 	 * @return
 	 */
 	public PagePart updatePart(PagePart part);
+	
+	public MediaHandler getMediaHandler(String type);
+	
+	public Media getMediaByKey(Long key);
+	
+	public List<Media> searchOwnedMedias(IdentityRef author);
+	
+	public void updateCategories(Media media, List<String> categories);
+	
 
 }
diff --git a/src/main/java/org/olat/modules/portfolio/handler/AbstractMediaHandler.java b/src/main/java/org/olat/modules/portfolio/handler/AbstractMediaHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4168dac37ee039019034ce16ae41e9aba11b625
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/handler/AbstractMediaHandler.java
@@ -0,0 +1,44 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.handler;
+
+import org.olat.modules.portfolio.MediaHandler;
+
+/**
+ * 
+ * Initial date: 20.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public abstract class AbstractMediaHandler implements MediaHandler {
+	
+	private final String type;
+	
+	public AbstractMediaHandler(String type) {
+		this.type = type;
+	}
+
+	@Override
+	public String getType() {
+		return type;
+	}
+	
+
+}
diff --git a/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java b/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java
index ef13c17c89b5e9adb2209d24dbd3f36595d80fe1..489c80795bc73d494f66d1005391b5308a33029d 100644
--- a/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java
+++ b/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java
@@ -474,7 +474,8 @@ public class BinderDAO {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select section from pfsection as section")
 		  .append(" inner join fetch section.baseGroup as baseGroup")
-		  .append(" where section.binder.key=:binderKey");
+		  .append(" where section.binder.key=:binderKey")
+		  .append(" order by section.pos");
 		
 		return dbInstance.getCurrentEntityManager()
 			.createQuery(sb.toString(), Section.class)
diff --git a/src/main/java/org/olat/modules/portfolio/manager/MediaDAO.java b/src/main/java/org/olat/modules/portfolio/manager/MediaDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..98b1dd892a52f29afa46f1f99317c97b5ffa6094
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/manager/MediaDAO.java
@@ -0,0 +1,93 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.manager;
+
+import java.util.Date;
+import java.util.List;
+
+import org.olat.basesecurity.IdentityRef;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.modules.portfolio.Media;
+import org.olat.modules.portfolio.model.MediaImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 17.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class MediaDAO {
+	
+	@Autowired
+	private DB dbInstance;
+	
+	public Media createMedia(String title, String description, String content, String type, String businessPath, int signature, Identity author) {
+		MediaImpl media = new MediaImpl();
+		media.setCreationDate(new Date());
+		media.setCollectionDate(media.getCreationDate());
+		media.setType(type);
+		
+		media.setTitle(title);
+		media.setDescription(description);
+		media.setContent(content);
+		media.setSignature(signature);
+		media.setBusinessPath(businessPath);
+		
+		media.setAuthor(author);
+		dbInstance.getCurrentEntityManager().persist(media);
+		return media;
+	}
+	
+	public Media updateStoragePath(Media media, String storagePath) {
+		((MediaImpl)media).setStoragePath(storagePath);
+		return dbInstance.getCurrentEntityManager().merge(media);
+	}
+	
+	public Media loadByKey(Long key) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select media from pfmedia as media")
+		  .append(" inner join fetch media.author as author")
+		  .append(" where media.key=:mediaKey");
+		
+		List<Media> medias = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Media.class)
+				.setParameter("mediaKey", key)
+				.getResultList();
+		return medias == null || medias.isEmpty() ? null : medias.get(0);
+	}
+	
+	public List<Media> loadByAuthor(IdentityRef author) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select media from pfmedia as media")
+		  .append(" inner join fetch media.author as author")
+		  .append(" where author.key=:authorKey");
+		
+		List<Media> medias = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Media.class)
+				.setParameter("authorKey", author.getKey())
+				.getResultList();
+		return medias;
+	}
+
+}
diff --git a/src/main/java/org/olat/modules/portfolio/manager/PortfolioFileStorage.java b/src/main/java/org/olat/modules/portfolio/manager/PortfolioFileStorage.java
index f0ecefe814590ee4a26ef7acaa3bdfdea4d34924..d0c76eafd22d28a1c8c426e6d2ab393e58f05146 100644
--- a/src/main/java/org/olat/modules/portfolio/manager/PortfolioFileStorage.java
+++ b/src/main/java/org/olat/modules/portfolio/manager/PortfolioFileStorage.java
@@ -24,6 +24,7 @@ import java.nio.file.Path;
 import java.util.UUID;
 
 import org.olat.core.commons.modules.bc.FolderConfig;
+import org.olat.modules.portfolio.Media;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.stereotype.Service;
 
@@ -37,7 +38,7 @@ import org.springframework.stereotype.Service;
 public class PortfolioFileStorage implements InitializingBean {
 	
 	private File rootDirectory, bcrootDirectory;
-	private File pagesPostersDirectory, binderPostersDirectory;
+	private File pagesPostersDirectory, binderPostersDirectory, mediaDirectory;
 	
 	@Override
 	public void afterPropertiesSet() {
@@ -50,13 +51,14 @@ public class PortfolioFileStorage implements InitializingBean {
 		File postersDirectory = new File(rootDirectory, "posters");
 		binderPostersDirectory = new File(postersDirectory, "binders");
 		pagesPostersDirectory = new File(postersDirectory, "pages");
+		mediaDirectory = new File(rootDirectory, "artefacts");
 	}
 	
 	protected File getRootDirectory() {
 		return bcrootDirectory;
 	}
 	
-	protected String getRelativePath(File file) {
+	public String getRelativePath(File file) {
 		Path relPath = bcrootDirectory.toPath().relativize(file.toPath());
 		return relPath.toString();
 	}
@@ -80,4 +82,19 @@ public class PortfolioFileStorage implements InitializingBean {
 		}
 		return dir;
 	}
+	
+	public File generateMediaSubDirectory(Media media) {
+		File subDirectory = generateMediaSubDirectory();
+		return new File(subDirectory, media.getKey().toString());
+	}
+	
+	protected File generateMediaSubDirectory() {
+		String cleanUuid = UUID.randomUUID().toString().replace("-", "");
+		String firstToken = cleanUuid.substring(0, 2).toLowerCase();
+		File dir = new File(mediaDirectory, firstToken);
+		if(!dir.exists()) {
+			dir.mkdirs();
+		}
+		return dir;
+	}
 }
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 f5713dc8ac830714fef54621934852897acb336f..b05c0cbb5fdaad7d6f3b8463a428db9ef9bb6d6f 100644
--- a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java
+++ b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java
@@ -41,6 +41,8 @@ import org.olat.core.util.resource.OresHelper;
 import org.olat.modules.portfolio.Binder;
 import org.olat.modules.portfolio.BinderRef;
 import org.olat.modules.portfolio.Category;
+import org.olat.modules.portfolio.Media;
+import org.olat.modules.portfolio.MediaHandler;
 import org.olat.modules.portfolio.Page;
 import org.olat.modules.portfolio.PageBody;
 import org.olat.modules.portfolio.PagePart;
@@ -75,6 +77,8 @@ public class PortfolioServiceImpl implements PortfolioService {
 	@Autowired
 	private GroupDAO groupDao;
 	@Autowired
+	private MediaDAO mediaDao;
+	@Autowired
 	private BinderDAO binderDao;
 	@Autowired
 	private CategoryDAO categoryDao;
@@ -87,6 +91,9 @@ public class PortfolioServiceImpl implements PortfolioService {
 	@Autowired
 	private PortfolioFileStorage portfolioFileStorage;
 	
+	@Autowired
+	private List<MediaHandler> mediaHandlers;
+	
 	@Override
 	public Binder createNewBinder(String title, String summary, String imagePath, Identity owner) {
 		BinderImpl portfolio = binderDao.createAndPersist(title, summary, imagePath, null);
@@ -275,7 +282,11 @@ public class PortfolioServiceImpl implements PortfolioService {
 	@Override
 	public void updateCategories(Binder binder, List<String> categories) {
 		OLATResourceable ores = OresHelper.createOLATResourceableInstance(Binder.class, binder.getKey());
-		List<Category> currentCategories = categoryDao.getCategories(ores);
+		updateCategories(ores, categories);
+	}
+
+	private void updateCategories(OLATResourceable oresource, List<String> categories) {
+		List<Category> currentCategories = categoryDao.getCategories(oresource);
 		Map<String,Category> currentCategoryMap = new HashMap<>();
 		for(Category category:currentCategories) {
 			currentCategoryMap.put(category.getName(), category);
@@ -285,14 +296,14 @@ public class PortfolioServiceImpl implements PortfolioService {
 		for(String newCategory:newCategories) {
 			if(!currentCategoryMap.containsKey(newCategory)) {
 				Category category = categoryDao.createAndPersistCategory(newCategory);
-				categoryDao.appendRelation(ores, category);
+				categoryDao.appendRelation(oresource, category);
 			}
 		}
 		
 		for(Category currentCategory:currentCategories) {
 			String name = currentCategory.getName();
 			if(!newCategories.contains(name)) {
-				categoryDao.removeRelation(ores, currentCategory);
+				categoryDao.removeRelation(oresource, currentCategory);
 			}
 		}
 	}
@@ -405,8 +416,33 @@ public class PortfolioServiceImpl implements PortfolioService {
 	public PagePart updatePart(PagePart part) {
 		return pageDao.merge(part);
 	}
-	
-	
-	
-	
+
+	@Override
+	public MediaHandler getMediaHandler(String type) {
+		if(this.mediaHandlers != null) {
+			for(MediaHandler handler:mediaHandlers) {
+				if(type.equals(handler.getType())) {
+					return handler;
+				}
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public void updateCategories(Media media, List<String> categories) {
+		OLATResourceable ores = OresHelper.createOLATResourceableInstance(Media.class, media.getKey());
+		updateCategories(ores, categories);
+	}
+
+	@Override
+	public List<Media> searchOwnedMedias(IdentityRef author) {
+		return mediaDao.loadByAuthor(author);
+	}
+
+	@Override
+	public Media getMediaByKey(Long key) {
+		return mediaDao.loadByKey(key);
+	}
+
 }
diff --git a/src/main/java/org/olat/modules/portfolio/model/MediaImpl.java b/src/main/java/org/olat/modules/portfolio/model/MediaImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..dba896956074c4a564335f4cfad784733eb1090c
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/model/MediaImpl.java
@@ -0,0 +1,202 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.model;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.olat.basesecurity.IdentityImpl;
+import org.olat.core.id.CreateInfo;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Persistable;
+import org.olat.modules.portfolio.Media;
+
+/**
+ * 
+ * Initial date: 17.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Entity(name="pfmedia")
+@Table(name="o_pf_media")
+public class MediaImpl implements Persistable, CreateInfo, Media  {
+
+	private static final long serialVersionUID = -8066676191014353560L;
+
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="p_collection_date", nullable=false, insertable=true, updatable=false)
+	private Date collectionDate;
+	@Column(name="p_type", nullable=false, insertable=true, updatable=false)
+	private String type;
+	@Column(name="p_storage_path", nullable=true, insertable=true, updatable=true)
+	private String storagePath;
+
+	@Column(name="p_title", nullable=false, insertable=true, updatable=true)
+	private String title;
+	@Column(name="p_description", nullable=true, insertable=true, updatable=true)
+	private String description;
+	@Column(name="p_content", nullable=true, insertable=true, updatable=true)
+	private String content;
+	@Column(name="p_signature", nullable=false, insertable=true, updatable=true)
+	private int signature;
+	@Column(name="p_business_path", nullable=false, insertable=true, updatable=true)
+	private String businessPath;
+
+	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_author_id", nullable=false, insertable=true, updatable=false)
+	private Identity author;
+
+	@Override
+	public Long getKey() {
+		return key;
+	}
+
+	public void setKey(Long key) {
+		this.key = key;
+	}
+
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
+	@Override
+	public Date getCollectionDate() {
+		return collectionDate;
+	}
+
+	public void setCollectionDate(Date collectionDate) {
+		this.collectionDate = collectionDate;
+	}
+
+	public String getType() {
+		return type;
+	}
+
+	public void setType(String type) {
+		this.type = type;
+	}
+
+	public String getStoragePath() {
+		return storagePath;
+	}
+
+	public void setStoragePath(String storagePath) {
+		this.storagePath = storagePath;
+	}
+
+	@Override
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	@Override
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public String getContent() {
+		return content;
+	}
+
+	public void setContent(String content) {
+		this.content = content;
+	}
+
+	public int getSignature() {
+		return signature;
+	}
+
+	public void setSignature(int signature) {
+		this.signature = signature;
+	}
+
+	@Override
+	public String getBusinessPath() {
+		return businessPath;
+	}
+
+	public void setBusinessPath(String businessPath) {
+		this.businessPath = businessPath;
+	}
+
+	@Override
+	public Identity getAuthor() {
+		return author;
+	}
+
+	public void setAuthor(Identity author) {
+		this.author = author;
+	}
+
+	@Override
+	public int hashCode() {
+		return key == null ? 459537 : key.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(obj == this) {
+			return true;
+		}
+		if(obj instanceof MediaImpl) {
+			MediaImpl media = (MediaImpl)obj;
+			return key != null && key.equals(media.getKey());
+		}
+		return false;
+	}
+
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+}
diff --git a/src/main/java/org/olat/modules/portfolio/model/MediaPart.java b/src/main/java/org/olat/modules/portfolio/model/MediaPart.java
new file mode 100644
index 0000000000000000000000000000000000000000..c06b3a33698c3152915eb2801982b20d2b58e288
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/model/MediaPart.java
@@ -0,0 +1,56 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.model;
+
+import javax.persistence.DiscriminatorColumn;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+
+import org.olat.modules.portfolio.Media;
+
+/**
+ * 
+ * Initial date: 17.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Entity(name="pfmediapart")
+@DiscriminatorColumn
+public class MediaPart extends AbstractPart {
+
+	private static final long serialVersionUID = -5902348088983758191L;
+	
+	@ManyToOne(targetEntity=MediaImpl.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="fk_media_id", nullable=false, insertable=true, updatable=false)
+	private Media media;
+
+	public Media getMedia() {
+		return media;
+	}
+
+	public void setMedia(Media media) {
+		this.media = media;
+	}
+	
+	
+
+}
diff --git a/src/main/java/org/olat/modules/portfolio/model/MediaRow.java b/src/main/java/org/olat/modules/portfolio/model/MediaRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..5eb0a27dad93e88d6d94af4ceacc57e005a58bc8
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/model/MediaRow.java
@@ -0,0 +1,57 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.model;
+
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.modules.portfolio.Media;
+
+/**
+ * 
+ * Initial date: 20.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MediaRow {
+	
+	private Media media;
+
+	private FormLink openFormLink;
+	
+	public MediaRow(Media media) {
+		this.media = media;
+	}
+	
+	public Long getKey() {
+		return media.getKey();
+	}
+	
+	public String getTitle() {
+		return media.getTitle();
+	}
+	
+	public FormLink getOpenFormItem() {
+		return openFormLink;
+	}
+	
+	public String getOpenFormItemName() {
+		return openFormLink == null ? null : openFormLink.getComponent().getComponentName();
+	}
+
+}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderRuntimeController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderRuntimeController.java
index 8a80cc32d8464bbcec30ec03ef3a17f5d13c5dbe..9f3c836377a3ea72f19a91def941232123596843 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/BinderRuntimeController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/BinderRuntimeController.java
@@ -1,3 +1,22 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
 package org.olat.modules.portfolio.ui;
 
 import org.olat.core.gui.UserRequest;
diff --git a/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java b/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java
index aa665dffcc6a3c11b15e83ffd9eba5c26a7967c9..1270218e738628a314ba8df3a43d968509a0dd9c 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java
@@ -19,12 +19,36 @@
  */
 package org.olat.modules.portfolio.ui;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponentDelegate;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRowCssDelegate;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
+import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.util.StringHelper;
+import org.olat.modules.portfolio.Media;
+import org.olat.modules.portfolio.PortfolioService;
+import org.olat.modules.portfolio.model.MediaRow;
+import org.olat.modules.portfolio.ui.BindersDataModel.PortfolioCols;
+import org.olat.modules.portfolio.ui.event.MediaSelectionEvent;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -32,34 +56,132 @@ import org.olat.core.gui.control.WindowControl;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class MediaCenterController extends FormBasicController {
+public class MediaCenterController extends FormBasicController implements FlexiTableComponentDelegate, FlexiTableRowCssDelegate {
+	
+	private MediaDataModel model;
+	private FlexiTableElement tableEl;
 	
+	private final boolean select;
 	private final TooledStackedPanel stackPanel;
+	
+	private MediaDetailsController detailsCtrl;
+	
+	@Autowired
+	private PortfolioService portfolioService;
 	 
+	public MediaCenterController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl, "medias");
+		this.stackPanel = null;
+		this.select = true;
+		 
+		initForm(ureq);
+		loadModel();
+	}
+	
 	public MediaCenterController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel) {
-		super(ureq, wControl);
+		super(ureq, wControl, "medias");
 		this.stackPanel = stackPanel;
+		this.select = false;
 		 
 		initForm(ureq);
+		loadModel();
 	}
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		setFormTitle("media.center");
+		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, PortfolioCols.key, "select"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(PortfolioCols.title, "select"));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(PortfolioCols.open));
+	
+		model = new MediaDataModel(columnsModel);
+		tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout);
+		tableEl.setAvailableRendererTypes(FlexiTableRendererType.custom, FlexiTableRendererType.classic);
+		tableEl.setRendererType(FlexiTableRendererType.custom);
+		tableEl.setSearchEnabled(true);
+		tableEl.setCustomizeColumns(true);
+		tableEl.setElementCssClass("o_binder_page_listing");
+		tableEl.setEmtpyTableMessageKey("table.sEmptyTable");
+		tableEl.setPageSize(24);
+		VelocityContainer row = createVelocityContainer("media_row");
+		row.setDomReplacementWrapperRequired(false); // sets its own DOM id in velocity container
+		tableEl.setRowRenderer(row, this);
+		tableEl.setRowCssDelegate(this);
+		tableEl.setAndLoadPersistedPreferences(ureq, "media-list");
+	}
+	
+	@Override
+	public String getRowCssClass(int pos) {
+		return null;
+	}
+
+	@Override
+	public Iterable<Component> getComponents(int row, Object rowObject) {
+		return null;
 	}
 	
+	private void loadModel() {
+		List<Media> medias = portfolioService.searchOwnedMedias(getIdentity());
+		List<MediaRow> rows = new ArrayList<>(medias.size());
+		for(Media media:medias) {
+			MediaRow row = new MediaRow(media);
+			rows.add(row);
+		}
+		model.setObjects(rows);
+	}
+
 	@Override
 	protected void doDispose() {
 		//
 	}
 
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(source == tableEl) {
+			if(event instanceof SelectionEvent) {
+				SelectionEvent se = (SelectionEvent)event;
+				String cmd = se.getCommand();
+				MediaRow row = model.getObject(se.getIndex());
+				if("select".equals(cmd)) {
+					if(select) {
+						doSelect(ureq, row.getKey());
+					} else {
+						doOpenMedia(ureq, row.getKey());
+					}
+				}
+			}
+		} else if(source instanceof FormLink) {
+			FormLink link = (FormLink)source;
+			String cmd = link.getCmd();
+			if("open".equals(cmd)) {
+				MediaRow row = (MediaRow)link.getUserObject();
+				Activateable2 activateable = doOpenMedia(ureq, row.getKey());
+				if(activateable != null) {
+					activateable.activate(ureq, null, null);
+				}
+			}
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+
 	@Override
 	protected void formOK(UserRequest ureq) {
 		//
 	}
+	
 
-
-	 
-	 
-
+	private void doSelect(UserRequest ureq, Long mediaKey) {
+		Media media = portfolioService.getMediaByKey(mediaKey);
+		fireEvent(ureq, new MediaSelectionEvent(media));
+	}
+	
+	private Activateable2 doOpenMedia(UserRequest ureq, Long mediaKey) {
+		Media media = portfolioService.getMediaByKey(mediaKey);
+		detailsCtrl = new MediaDetailsController(ureq, getWindowControl(), media);
+		listenTo(detailsCtrl);
+		
+		String displayName = StringHelper.escapeHtml(media.getTitle());
+		stackPanel.pushController(displayName, detailsCtrl);
+		return detailsCtrl;
+	}
 }
diff --git a/src/main/java/org/olat/modules/portfolio/ui/MediaDataModel.java b/src/main/java/org/olat/modules/portfolio/ui/MediaDataModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..4bbebd81b8a7654117d1d6c7ddc5469dd421b7e3
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/MediaDataModel.java
@@ -0,0 +1,82 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.ui;
+
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.modules.portfolio.model.MediaRow;
+import org.olat.modules.portfolio.ui.PageListDataModel.PageCols;
+
+/**
+ * 
+ * Initial date: 20.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MediaDataModel  extends DefaultFlexiTableDataModel<MediaRow>  {
+	
+	public MediaDataModel(FlexiTableColumnModel columnsModel) {
+		super(columnsModel);
+	}
+
+	@Override
+	public Object getValueAt(int row, int col) {
+		MediaRow page = getObject(row);
+		switch(PageCols.values()[col]) {
+			case key: return page.getKey();
+			case title: return page.getTitle();
+			case open: return page.getOpenFormItem();
+		}
+		return null;
+	}
+	
+		@Override
+	public DefaultFlexiTableDataModel<MediaRow> createCopyWithEmptyList() {
+		return new MediaDataModel(getTableColumnModel());
+	}
+		
+	public enum MediaCols implements FlexiSortableColumnDef {
+		key("table.header.key"),
+		title("table.header.title"),
+		open("table.header.open");
+
+		private final String i18nKey;
+		
+		private MediaCols(String i18nKey) {
+			this.i18nKey = i18nKey;
+		}
+		
+		@Override
+		public String i18nHeaderKey() {
+			return i18nKey;
+		}
+
+		@Override
+		public boolean sortable() {
+			return true;
+		}
+
+		@Override
+		public String sortKey() {
+			return name();
+		}
+	}
+}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java b/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java
new file mode 100644
index 0000000000000000000000000000000000000000..03ca20399722374b4713d262f2fa82ba60a0e2dc
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java
@@ -0,0 +1,94 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.ui;
+
+import java.util.List;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.StringHelper;
+import org.olat.modules.portfolio.Media;
+import org.olat.modules.portfolio.MediaHandler;
+import org.olat.modules.portfolio.PortfolioService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 20.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MediaDetailsController extends FormBasicController implements Activateable2 {
+	
+	private Media media;
+	private MediaHandler handler;
+	
+	private Controller mediaCtrl;
+	
+	@Autowired
+	private PortfolioService portfolioService;
+	
+	public MediaDetailsController(UserRequest ureq, WindowControl wControl, Media media) {
+		super(ureq, wControl, "media_details");
+		this.media = media;
+		handler = portfolioService.getMediaHandler(media.getType());
+		
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		
+		if(formLayout instanceof FormLayoutContainer) {
+			FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout;
+			layoutCont.contextPut("title", StringHelper.escapeHtml(media.getTitle()));
+			layoutCont.contextPut("description", StringHelper.xssScan(media.getDescription()));
+			layoutCont.contextPut("iconCssClass", handler.getIconCssClass());
+			
+			mediaCtrl = handler.getMediaController(ureq, getWindowControl(), media);
+			if(mediaCtrl != null) {
+				listenTo(mediaCtrl);
+				layoutCont.put("media", mediaCtrl.getInitialComponent());
+			}
+		}
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/PageController.java b/src/main/java/org/olat/modules/portfolio/ui/PageController.java
index 436ab3a7238ee7fe6c3d08fa49889fd0c423f40f..c8023c39db70be8105df7126f59b3e3bb0484ad0 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/PageController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/PageController.java
@@ -32,17 +32,22 @@ import org.olat.core.gui.components.link.LinkFactory;
 import org.olat.core.gui.components.stack.TooledController;
 import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.components.stack.TooledStackedPanel.Align;
+import org.olat.core.gui.components.text.TextComponent;
+import org.olat.core.gui.components.text.TextFactory;
 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.generic.closablewrapper.CloseableModalController;
+import org.olat.core.util.CodeHelper;
 import org.olat.modules.portfolio.Binder;
 import org.olat.modules.portfolio.BinderSecurityCallback;
+import org.olat.modules.portfolio.MediaHandler;
 import org.olat.modules.portfolio.Page;
 import org.olat.modules.portfolio.PagePart;
 import org.olat.modules.portfolio.PortfolioService;
 import org.olat.modules.portfolio.Section;
 import org.olat.modules.portfolio.model.HTMLPart;
+import org.olat.modules.portfolio.model.MediaPart;
 import org.olat.modules.portfolio.ui.editor.PageEditorController;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -56,12 +61,13 @@ public class PageController extends FormBasicController implements TooledControl
 
 	private Link editLink, editMetadataLink;
 	protected final TooledStackedPanel stackPanel;
-	private List<HTMLFragment> fragments = new ArrayList<>();
+	private List<FragmentWrapper> fragments = new ArrayList<>();
 	
 	private CloseableModalController cmc;
 	private PageEditorController editCtrl;
 	private PageMetadataEditController editMetadataCtrl;
 	
+	private int counter;
 	private Page page;
 	private final BinderSecurityCallback secCallback;
 	
@@ -76,7 +82,7 @@ public class PageController extends FormBasicController implements TooledControl
 		this.secCallback = secCallback;
 		
 		initForm(ureq);
-		loadModel();
+		loadModel(ureq);
 	}
 
 	@Override
@@ -102,15 +108,17 @@ public class PageController extends FormBasicController implements TooledControl
 		}
 	}
 	
-	private void loadModel() {
+	private void loadModel(UserRequest ureq) {
 		flc.getFormItemComponent().contextPut("pageTitle", page.getTitle());
 		
 		List<PagePart> parts = portfolioService.getPageParts(page);
-		List<HTMLFragment> newFragments = new ArrayList<>(parts.size());
+		List<FragmentWrapper> newFragments = new ArrayList<>(parts.size());
 		for(PagePart part:parts) {
-			HTMLFragment fragment = createFragment(part);
+			Fragment fragment = createFragment(ureq, part);
 			if(fragment != null) {
-				newFragments.add(fragment);
+				String cmpId = "cpt-" + (++counter);
+				newFragments.add(new FragmentWrapper(cmpId, fragment.getContent()));
+				flc.getFormItemComponent().put(cmpId, fragment.getContent());
 			}
 		}
 		fragments = newFragments;
@@ -126,10 +134,10 @@ public class PageController extends FormBasicController implements TooledControl
 	public void event(UserRequest ureq, Controller source, Event event) {
 		if(editCtrl == source) {
 			stackPanel.popUpToController(this);
-			loadModel();
+			loadModel(ureq);
 		} else if(editMetadataCtrl == source) {
 			if(event == Event.DONE_EVENT) {
-				loadModel();
+				loadModel(ureq);
 			}
 			cmc.deactivate();
 			cleanUp();
@@ -191,34 +199,82 @@ public class PageController extends FormBasicController implements TooledControl
 		stackPanel.pushController("Edit", editCtrl);
 	}
 	
-	private HTMLFragment createFragment(PagePart part) {
+	private Fragment createFragment(UserRequest ureq, PagePart part) {
 		if(part instanceof HTMLPart) {
 			HTMLPart htmlPart = (HTMLPart)part;
 			HTMLFragment editorFragment = new HTMLFragment(htmlPart);
 			return editorFragment;
+		} else if(part instanceof MediaPart) {
+			MediaPart htmlPart = (MediaPart)part;
+			MediaFragment editorFragment = new MediaFragment(htmlPart, ureq);
+			return editorFragment;
 		}
 		return null;
-		
 	}
 	
-	public static class HTMLFragment {
+	public class MediaFragment implements Fragment {
 		
-		private PagePart part;
+		private final PagePart part;
+		private Controller controller;
 		
-		public HTMLFragment(HTMLPart part) {
+		public MediaFragment(MediaPart part, UserRequest ureq) {
 			this.part = part;
+			MediaHandler handler = portfolioService.getMediaHandler(part.getMedia().getType());
+			controller = handler.getMediaController(ureq, getWindowControl(), part.getMedia());
 		}
 		
-		public String getContent() {
-			return part.getContent();
+		@Override
+		public Component getContent() {
+			return controller.getInitialComponent();
 		}
 
 		public PagePart getPart() {
 			return part;
 		}
+	}
+	
+	public static class HTMLFragment implements Fragment {
+		
+		private final PagePart part;
+		private TextComponent component;
 		
-		public void setPart(PagePart part) {
+		public HTMLFragment(HTMLPart part) {
 			this.part = part;
+			component = TextFactory.createTextComponentFromString("cmp" + CodeHelper.getRAMUniqueID(), part.getContent(), null, false, null);
+		}
+
+		@Override
+		public Component getContent() {
+			return component;
+		}
+
+		public PagePart getPart() {
+			return part;
+		}
+	}
+	
+	public interface Fragment {
+		
+		public Component getContent();
+		
+	}
+	
+	public static final class FragmentWrapper {
+		
+		private final String componentName;
+		private final Component component;
+		
+		public FragmentWrapper(String componentName, Component component) {
+			this.componentName = componentName;
+			this.component = component;
+		}
+		
+		public String getComponentName() {
+			return componentName;
+		}
+		
+		public Component getComponent() {
+			return component;
 		}
 	}
 }
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html b/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html
new file mode 100644
index 0000000000000000000000000000000000000000..faf960c0f61bfe76306c34d08eaec10a8a7727e3
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/_content/media_details.html
@@ -0,0 +1,5 @@
+<h2><i class="o_icon o_icon-lg $iconCssClass"> </i> $title</h2>
+
+<div class="clearfix">
+$r.render("media")
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/media_row.html b/src/main/java/org/olat/modules/portfolio/ui/_content/media_row.html
new file mode 100644
index 0000000000000000000000000000000000000000..5ab2f8a4323abafb10abb68657d9d39f1a775057
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/_content/media_row.html
@@ -0,0 +1 @@
+Hello
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/medias.html b/src/main/java/org/olat/modules/portfolio/ui/_content/medias.html
new file mode 100644
index 0000000000000000000000000000000000000000..bade9402acda206e8171adcb2d85adb1b884ea54
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/_content/medias.html
@@ -0,0 +1 @@
+$r.render("table")
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/page_content.html b/src/main/java/org/olat/modules/portfolio/ui/_content/page_content.html
index c298d097debad73fe54e7d4d4d18f6133850c8b8..eb31c305035b8997ac658b5ac6b273d20c2f88c2 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/_content/page_content.html
+++ b/src/main/java/org/olat/modules/portfolio/ui/_content/page_content.html
@@ -1,4 +1,4 @@
 <h1>$pageTitle</h1>
 #foreach($fragment in $fragments)
-	<div class="">$fragment.content</div>
+	<div class="">$r.render($fragment.componentName)</div>
 #end
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties
index 828105f4907387556d985c58188e1ba367107f84..8b6f5e97ba23fa303bbfd0513f9c99b6b04f57a4 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties
@@ -3,6 +3,11 @@
 access.rights.owner.long=als Besitzer (lesen / schreiben)
 access.rights.coach.long=als Betreuer (lesen / kommentieren / bewerten)
 access.rights.reviewer.long=als Reviewer (lesen / kommentieren)
+artefact.collect.date=Datum
+
+artefact.descr=Beschreibung
+artefact.title=Titel
+artefact.source=Quelle
 meta.last.modified=zuletzt bearbeitet am {0}
 portfolio.personal.menu.title=Portfolio 2.0
 portfolio.personal.menu.title.alt=$\:portfolio.personal.menu.title
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties
index 1270d43dedb646801ef7a39e4047122e15a10d9c..8fa1662f6bfc589ccff444fb43622be014393eab 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties
@@ -15,8 +15,14 @@ access.rights.date=Date
 access.rights.owner.long=as owner (read / write)
 access.rights.coach.long=as coach (read / comment / assess)
 access.rights.reviewer.long=as reviewer (read / comment)
-add.html=HTML
+add.html=Add HTML
+add.media=Add media
 add.member=Add member
+artefact.collect.date=Date
+artefact.collect.link=Link
+artefact.descr=Description
+artefact.title=Title
+artefact.source=Source
 begin.date=Begin
 binder.by=by {0}
 categories=Categories
diff --git a/src/main/java/org/olat/modules/portfolio/ui/component/MediaCollectorComponent.java b/src/main/java/org/olat/modules/portfolio/ui/component/MediaCollectorComponent.java
new file mode 100644
index 0000000000000000000000000000000000000000..f1af63f6d6dfd0010923364bbe7b63b98b67b97d
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/component/MediaCollectorComponent.java
@@ -0,0 +1,112 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.ui.component;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.ComponentRenderer;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.impl.FormBaseComponentImpl;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.ControllerEventListener;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
+import org.olat.modules.portfolio.MediaHandler;
+import org.olat.modules.portfolio.ui.wizard.CollectArtefactController;
+
+/**
+ * 
+ * Initial date: 17.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MediaCollectorComponent extends FormBaseComponentImpl implements ControllerEventListener {
+	
+	private CloseableModalController cmc;
+	private CollectArtefactController collectorCtrl;
+	
+	private static final ComponentRenderer RENDERER = new MediaCollectorComponentRenderer();
+
+	private FormItem item;
+	private final WindowControl wControl;
+	
+	private final Object media;
+	private final String businessPath;
+	private final MediaHandler handler;
+	
+	public MediaCollectorComponent(String name, WindowControl wControl, Object media, MediaHandler handler, String businessPath) {
+		super(name);
+		this.wControl = wControl;
+		this.media = media;
+		this.handler = handler;
+		this.businessPath = businessPath;
+	}
+	
+	public FormItem getItem() {
+		return item;
+	}
+
+	@Override
+	protected void doDispatchRequest(UserRequest ureq) {
+		String cmd = ureq.getParameter(VelocityContainer.COMMAND_ID);
+		if("pfcollect".equalsIgnoreCase(cmd)) {
+			doOpenCollector(ureq);
+		}
+	}
+
+	@Override
+	public void dispatchEvent(UserRequest ureq, Controller source, Event event) {
+		if(collectorCtrl == source) {
+			
+			cmc.deactivate();
+			cleanUp();
+		} else if(cmc == source) {
+			cleanUp();
+		}
+	}
+	
+	private void cleanUp() {
+		if(collectorCtrl != null) {
+			//collectorCtrl.addControllerListener(el);
+			collectorCtrl = null;
+		}
+		if(cmc != null) {
+			cmc = null;
+		}
+		
+	}
+
+	private void doOpenCollector(UserRequest ureq) {
+		collectorCtrl = new CollectArtefactController(ureq, wControl, media, handler, businessPath);
+		collectorCtrl.addControllerListener(this);
+		
+		String title = "Media";
+		cmc = new CloseableModalController(wControl, null, collectorCtrl.getInitialComponent(), true, title, true);
+		cmc.addControllerListener(this);
+		cmc.activate();
+		
+	}
+
+	@Override
+	public ComponentRenderer getHTMLRendererSingleton() {
+		return RENDERER;
+	}
+}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/component/MediaCollectorComponentRenderer.java b/src/main/java/org/olat/modules/portfolio/ui/component/MediaCollectorComponentRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..03a4ae529d3bed286ef28f777a2c1e7edb660139
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/component/MediaCollectorComponentRenderer.java
@@ -0,0 +1,57 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.ui.component;
+
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.DefaultComponentRenderer;
+import org.olat.core.gui.components.form.flexible.impl.NameValuePair;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.render.RenderResult;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
+import org.olat.core.gui.translator.Translator;
+
+/**
+ * 
+ * Initial date: 17.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MediaCollectorComponentRenderer extends DefaultComponentRenderer {
+
+	@Override
+	public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator,
+			RenderResult renderResult, String[] args) {
+		MediaCollectorComponent cmp = (MediaCollectorComponent)source;
+		sb.append("<a class='o_portfolio_collector' ");
+		
+		if(cmp.getItem() == null) {
+			ubu.buildHrefAndOnclick(sb, null, true, false, true,
+					new NameValuePair(VelocityContainer.COMMAND_ID, "pfcollect"));
+		}
+		
+		
+		
+		sb.append("><i class='o_icon o_icon-lg o_icon_eportfolio_add'> </i></a>");
+	}
+
+	
+}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/editor/PageEditorController.java b/src/main/java/org/olat/modules/portfolio/ui/editor/PageEditorController.java
index 963c96e4e8f69e6fd1ca35a4c337bf2fc5ec4bd0..d1027af1b30a52a5e3a2b6080bbdfd226aa61f97 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/editor/PageEditorController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/editor/PageEditorController.java
@@ -34,14 +34,19 @@ import org.olat.core.gui.components.link.Link;
 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.generic.closablewrapper.CloseableModalController;
 import org.olat.core.util.StringHelper;
-import org.olat.core.util.UserSession;
 import org.olat.core.util.Util;
+import org.olat.modules.portfolio.Media;
+import org.olat.modules.portfolio.MediaHandler;
 import org.olat.modules.portfolio.Page;
 import org.olat.modules.portfolio.PagePart;
 import org.olat.modules.portfolio.PortfolioService;
 import org.olat.modules.portfolio.model.HTMLPart;
+import org.olat.modules.portfolio.model.MediaPart;
+import org.olat.modules.portfolio.ui.MediaCenterController;
 import org.olat.modules.portfolio.ui.PageController;
+import org.olat.modules.portfolio.ui.event.MediaSelectionEvent;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -52,9 +57,12 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class PageEditorController extends FormBasicController {
 
-	private FormLink addHtmlLink;
-	private List<HTMLEditorFragment> fragments = new ArrayList<>();
+	private FormLink addHtmlLink, addMediaLink;
+	private List<EditorFragment> fragments = new ArrayList<>();
 
+	private CloseableModalController cmc;
+	private MediaCenterController mediaListCtrl;
+	
 	private Page page;
 	private int counter = 0;
 	
@@ -74,6 +82,9 @@ public class PageEditorController extends FormBasicController {
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		addHtmlLink = uifactory.addFormLink("add.html", "add.html", "add.html", null, formLayout, Link.BUTTON);
 		addHtmlLink.setIconLeftCSS("o_icon o_icon_add_html");
+		
+		addMediaLink = uifactory.addFormLink("add.media", "add.media", "add.media", null, formLayout, Link.BUTTON);
+		addMediaLink.setIconLeftCSS("o_icon o_icon_portfolio");
 			
 		uifactory.addFormSubmitButton("save", formLayout);
 
@@ -84,11 +95,10 @@ public class PageEditorController extends FormBasicController {
 	}
 	
 	private void loadModel(UserRequest ureq) {
-		UserSession usess = ureq.getUserSession();
 		List<PagePart> parts = portfolioService.getPageParts(page);
-		List<HTMLEditorFragment> newFragments = new ArrayList<>(parts.size());
+		List<EditorFragment> newFragments = new ArrayList<>(parts.size());
 		for(PagePart part:parts) {
-			HTMLEditorFragment fragment = createFragment(part, usess);
+			EditorFragment fragment = createFragment(ureq, part);
 			if(fragment != null) {
 				newFragments.add(fragment);
 			}
@@ -106,6 +116,8 @@ public class PageEditorController extends FormBasicController {
 	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if(addHtmlLink == source) {
 			doAddHTMLFragment(ureq);
+		} else if(addMediaLink == source) {
+			doOpenMediaBrowser(ureq);
 		} else if(source.getUserObject() instanceof HTMLEditorFragment) {
 			HTMLEditorFragment fragment = (HTMLEditorFragment)source.getUserObject();
 			if(fragment.getFormItem() == source) {
@@ -127,48 +139,104 @@ public class PageEditorController extends FormBasicController {
 
 	@Override
 	protected void formOK(UserRequest ureq) {
-		for(HTMLEditorFragment fragment:fragments) {
-			String htmlVal = fragment.getFormItem().getValue();
-			String currentHtmlVal = fragment.getPart().getContent();
-			
-			if((currentHtmlVal == null && StringHelper.containsNonWhitespace(htmlVal))
-					|| (htmlVal == null && StringHelper.containsNonWhitespace(currentHtmlVal))
-					|| (currentHtmlVal != null && !currentHtmlVal.equals(htmlVal))) {
-				PagePart part = fragment.getPart();
-				part.setContent(htmlVal);
-				fragment.setPart(portfolioService.updatePart(part));
+		for(EditorFragment fragment:fragments) {
+			if(fragment instanceof HTMLEditorFragment) {
+				HTMLEditorFragment htmlFragment = (HTMLEditorFragment)fragment;
+				String htmlVal = htmlFragment.getFormItem().getValue();
+				String currentHtmlVal = fragment.getPart().getContent();
+				
+				if((currentHtmlVal == null && StringHelper.containsNonWhitespace(htmlVal))
+						|| (htmlVal == null && StringHelper.containsNonWhitespace(currentHtmlVal))
+						|| (currentHtmlVal != null && !currentHtmlVal.equals(htmlVal))) {
+					PagePart part = fragment.getPart();
+					part.setContent(htmlVal);
+					htmlFragment.setPart(portfolioService.updatePart(part));
+				}
 			}
 		}
 		fireEvent(ureq, Event.DONE_EVENT);
 	}
 	
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if(mediaListCtrl == source) {
+			if(event instanceof MediaSelectionEvent) {
+				MediaSelectionEvent mse = (MediaSelectionEvent)event;
+				if(mse.getMedia() != null) {
+					doAddMedia(ureq, mse.getMedia());
+				}
+			}
+			cmc.deactivate();
+			cleanUp();
+		} else if(cmc == source) {
+			cleanUp();
+		}
+		super.event(ureq, source, event);
+	}
+	
+	private void cleanUp() {
+		removeAsListenerAndDispose(mediaListCtrl);
+		removeAsListenerAndDispose(cmc);
+		mediaListCtrl = null;
+		cmc = null;
+	}
+
+	private void doOpenMediaBrowser(UserRequest ureq) {
+		if(mediaListCtrl != null) return;
+		
+		mediaListCtrl = new MediaCenterController(ureq, getWindowControl());
+		listenTo(mediaListCtrl);
+		
+		String title = translate("add.media");
+		cmc = new CloseableModalController(getWindowControl(), null, mediaListCtrl.getInitialComponent(), true, title, true);
+		listenTo(cmc);
+		cmc.activate();
+	}
+	
+	private void doAddMedia(UserRequest ureq, Media media) {
+		MediaPart part = new MediaPart();
+		part.setMedia(media);
+		part = portfolioService.appendNewPagePart(page, part);
+		EditorFragment fragment = createFragment(ureq, part);
+		fragments.add(fragment);
+		flc.setDirty(true);
+	}
+	
 	private void doAddHTMLFragment(UserRequest ureq) {
 		String content = "<p>Hello world</p>";
 		HTMLPart htmlPart = new HTMLPart();
 		htmlPart.setContent(content);
 		htmlPart = portfolioService.appendNewPagePart(page, htmlPart);
-		HTMLEditorFragment fragment = createFragment(htmlPart, ureq.getUserSession());
+		EditorFragment fragment = createFragment(ureq, htmlPart);
 		fragments.add(fragment);
 		flc.setDirty(true);
 	}
 	
-	private HTMLEditorFragment createFragment(PagePart part, UserSession usess) {
+	private EditorFragment createFragment(UserRequest ureq, PagePart part) {
 		if(part instanceof HTMLPart) {
 			HTMLPart htmlPart = (HTMLPart)part;
 			HTMLEditorFragment editorFragment = new HTMLEditorFragment(htmlPart);
 			
 			String cmpId = "html-" + (++counter);
 			String content = htmlPart.getContent();
-			RichTextElement htmlItem = uifactory.addRichTextElementForStringDataCompact(cmpId, null, content, 25, 80, null, flc, usess, getWindowControl());
+			RichTextElement htmlItem = uifactory.addRichTextElementForStringDataCompact(cmpId, null, content, 25, 80, null, flc, ureq.getUserSession(), getWindowControl());
 			//htmlItem.getEditorConfiguration().setInline(true);
 			editorFragment.setFormItem(htmlItem);
 			return editorFragment;
+		} else if (part instanceof MediaPart) {
+			MediaPart mediaPart = (MediaPart)part;
+			MediaHandler handler = portfolioService.getMediaHandler(mediaPart.getMedia().getType());
+			String cmpId = "media-" + (++counter);
+			Controller mediaCtrl = handler.getMediaController(ureq, getWindowControl(), mediaPart.getMedia());
+			MediaEditorFragment fragment = new MediaEditorFragment(mediaPart, cmpId, mediaCtrl);
+			flc.getFormItemComponent().put(cmpId, mediaCtrl.getInitialComponent());
+			return fragment;
 		}
 		return null;
 		
 	}
 	
-	public static class HTMLEditorFragment {
+	public static class HTMLEditorFragment implements EditorFragment {
 		
 		private PagePart part;
 		private RichTextElement formItem;
@@ -177,6 +245,7 @@ public class PageEditorController extends FormBasicController {
 			this.part = part;
 		}
 
+		@Override
 		public PagePart getPart() {
 			return part;
 		}
@@ -193,9 +262,46 @@ public class PageEditorController extends FormBasicController {
 			this.formItem = formItem;
 			formItem.setUserObject(this);
 		}
-		
+
+		@Override
 		public String getComponentName() {
 			return formItem.getComponent().getComponentName();
 		}
 	}
+	
+	public static class MediaEditorFragment implements EditorFragment {
+		
+		private PagePart part;
+		private String cmpName;
+		private Controller controller;
+		
+		public MediaEditorFragment(MediaPart part, String cmpName, Controller controller) {
+			this.part = part;
+			this.cmpName = cmpName;
+			this.controller = controller;
+		}
+
+		@Override
+		public PagePart getPart() {
+			return part;
+		}
+		
+		public void setPart(PagePart part) {
+			this.part = part;
+		}
+
+		@Override
+		public String getComponentName() {
+			return cmpName;
+		}
+	}
+	
+	public interface EditorFragment {
+		
+		public PagePart getPart();
+		
+		public void setPart(PagePart part);
+		
+		public String getComponentName();
+	}
 }
diff --git a/src/main/java/org/olat/modules/portfolio/ui/editor/_content/page_editor.html b/src/main/java/org/olat/modules/portfolio/ui/editor/_content/page_editor.html
index 281a62fb4bbd2ccbffa79ddaf92006b87d3f70b8..e2a30f54c072282bf0bd30013ee258c7a5def460 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/editor/_content/page_editor.html
+++ b/src/main/java/org/olat/modules/portfolio/ui/editor/_content/page_editor.html
@@ -1,6 +1,6 @@
 <h1>$pageTitle</h1>
 <div class="o_button_group o_button_group_left">
-$r.render("save") $r.render("add.html")
+$r.render("save") $r.render("add.html") $r.render("add.media")
 </div>
 
 #foreach($fragment in $fragments)
diff --git a/src/main/java/org/olat/modules/portfolio/ui/event/MediaSelectionEvent.java b/src/main/java/org/olat/modules/portfolio/ui/event/MediaSelectionEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..20b8aaadd47998ed0d54ff9c74ee4b8e4c03f55e
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/event/MediaSelectionEvent.java
@@ -0,0 +1,44 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.ui.event;
+
+import org.olat.core.gui.control.Event;
+import org.olat.modules.portfolio.Media;
+
+/**
+ * 
+ * Initial date: 20.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MediaSelectionEvent extends Event {
+
+	private static final long serialVersionUID = -7111363042350387554L;
+	private Media media;
+	
+	public MediaSelectionEvent(Media media) {
+		super("pf-media-select");
+		this.media = media;
+	}
+
+	public Media getMedia() {
+		return media;
+	}
+}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/wizard/CollectArtefactController.java b/src/main/java/org/olat/modules/portfolio/ui/wizard/CollectArtefactController.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8bc46d70509bafe8f7beaf039969067ee1f64a6
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/wizard/CollectArtefactController.java
@@ -0,0 +1,139 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.ui.wizard;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.StaticTextElement;
+import org.olat.core.gui.components.form.flexible.elements.TextBoxListElement;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.context.BusinessControlFactory;
+import org.olat.core.util.Formatter;
+import org.olat.core.util.Util;
+import org.olat.modules.portfolio.Media;
+import org.olat.modules.portfolio.MediaHandler;
+import org.olat.modules.portfolio.PortfolioService;
+import org.olat.modules.portfolio.ui.PortfolioHomeController;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 20.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CollectArtefactController extends FormBasicController {
+	
+	private TextElement titleEl;
+	private TextElement descriptionEl;
+	private TextBoxListElement categoriesEl;
+	
+	private StaticTextElement sourceEl;
+	private StaticTextElement dateEl;
+	private StaticTextElement linkEl;
+
+	private Media mediaReference;
+	private final Object mediaObject;
+	private final MediaHandler handler;
+	private Map<String,String> categories = new HashMap<>();
+	
+	private final String businessPath;
+	
+	@Autowired
+	private PortfolioService portfolioService;
+
+	public CollectArtefactController(UserRequest ureq, WindowControl wControl, Object mediaObject, MediaHandler handler, String businessPath) {
+		super(ureq, wControl);
+		setTranslator(Util.createPackageTranslator(PortfolioHomeController.class, getLocale(), getTranslator()));
+		this.handler = handler;
+		this.mediaObject = mediaObject; 
+		this.businessPath = businessPath;
+		
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		titleEl = uifactory.addTextElement("artefact.title", "artefact.title", 255, "", formLayout);
+		titleEl.setMandatory(true);
+		
+		descriptionEl = uifactory.addRichTextElementForStringData("artefact.descr", "artefact.descr", "", 8, 6, false, null, null, formLayout, ureq.getUserSession(), getWindowControl());
+		
+		categoriesEl = uifactory.addTextBoxListElement("categories", "categories", "categories.hint", categories, formLayout, getTranslator());
+		categoriesEl.setElementCssClass("o_sel_ep_tagsinput");
+		categoriesEl.setAllowDuplicates(false);
+		
+		String source = "Forum";
+		uifactory.addStaticTextElement("artefact.source", "artefact.source", source, formLayout);
+		String date = Formatter.getInstance(getLocale()).formatDate(new Date());
+		uifactory.addStaticTextElement("artefact.collect.date", "artefact.collect.date", date, formLayout);
+
+		String link = BusinessControlFactory.getInstance().getURLFromBusinessPathString(businessPath);
+		uifactory.addStaticTextElement("artefact.collect.link", "artefact.collect.link", link, formLayout);
+		
+		FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		formLayout.add(buttonsCont);
+		uifactory.addFormSubmitButton("save", "save", buttonsCont);
+		uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl());
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = true;
+
+		return allOk & super.validateFormLogic(ureq);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		if(mediaReference == null) {
+			String title = titleEl.getValue();
+			String description = descriptionEl.getValue();
+			mediaReference = handler.createMedia(title, description, mediaObject, businessPath, getIdentity());
+		} else {
+			//TODO
+		}
+
+		List<String> updatedCategories = categoriesEl.getValueList();
+		portfolioService.updateCategories(mediaReference, updatedCategories);
+		
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+	
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml
index 16ae4e66012842a2c5d18d8a0b4cae1daa4ea7ae..3c1a751688fd649439e2ca3e58b63d748fd032f8 100644
--- a/src/main/resources/META-INF/persistence.xml
+++ b/src/main/resources/META-INF/persistence.xml
@@ -160,7 +160,9 @@
 		<class>org.olat.modules.portfolio.model.PageImpl</class>
 		<class>org.olat.modules.portfolio.model.PageBodyImpl</class>
 		<class>org.olat.modules.portfolio.model.AbstractPart</class>
+		<class>org.olat.modules.portfolio.model.MediaImpl</class>
 		<class>org.olat.modules.portfolio.model.HTMLPart</class>
+		<class>org.olat.modules.portfolio.model.MediaPart</class>
 		<class>org.olat.modules.portfolio.model.CategoryImpl</class>
 		<class>org.olat.modules.portfolio.model.CategoryToElementImpl</class>
 		<class>org.olat.modules.qpool.model.PoolImpl</class>
diff --git a/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql b/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql
index b7b2df2a9f21eee3d8ea0a4ba91b96170fe1ec91..a9f1e41084a8178ea57eaaea17e62be3f91aac6b 100644
--- a/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql
+++ b/src/main/resources/database/mysql/alter_10_x_0_to_11_0_0.sql
@@ -190,6 +190,26 @@ alter table o_pf_page_body ENGINE = InnoDB;
 alter table o_pf_page add constraint pf_page_body_idx foreign key (fk_body_id) references o_pf_page_body (id);
 
 
+create table o_pf_media (
+   id bigint not null auto_increment,
+   creationdate datetime not null,
+   p_collection_date datetime not null,
+   p_type varchar(64) not null,
+   p_storage_path varchar(255),
+   p_title varchar(255) not null,
+   p_description mediumtext,
+   p_content mediumtext,
+   p_signature bigint not null default 0,
+   p_business_path varchar(255) not null,
+   fk_author_id bigint not null,
+   primary key (id)
+);
+alter table o_pf_media ENGINE = InnoDB;
+
+alter table o_pf_media add constraint pf_media_author_idx foreign key (fk_author_id) references o_bs_identity (id);
+create index idx_media_storage_path_idx on o_pf_media (p_business_path);
+
+
 create table o_pf_page_part (
    id bigint not null auto_increment,
    creationdate datetime not null,
@@ -197,12 +217,14 @@ create table o_pf_page_part (
    pos bigint default null,
    dtype varchar(32),
    p_content mediumtext,
+   fk_media_id bigint,
    fk_page_body_id bigint,
    primary key (id)
 );
 alter table o_pf_page_part ENGINE = InnoDB;
 
 alter table o_pf_page_part add constraint pf_page_page_body_idx foreign key (fk_page_body_id) references o_pf_page_body (id);
+alter table o_pf_page_part add constraint pf_page_media_idx foreign key (fk_media_id) references o_pf_media (id);
 
 
 create table o_pf_category (
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index 053a4944084764ebe84b67fa013747a778c798c1..d9808b1dee2c9647af5f41314eb93e98947c801f 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1603,7 +1603,6 @@ create table o_pf_binder (
    primary key (id)
 );
 
-
 create table o_pf_section (
    id bigint not null auto_increment,
    creationdate datetime not null,
@@ -1620,7 +1619,6 @@ create table o_pf_section (
    primary key (id)
 );
 
-
 create table o_pf_page (
    id bigint not null auto_increment,
    creationdate datetime not null,
@@ -1646,6 +1644,20 @@ create table o_pf_page_body (
    primary key (id)
 );
 
+create table o_pf_media (
+   id bigint not null auto_increment,
+   creationdate datetime not null,
+   p_collection_date datetime not null,
+   p_type varchar(64) not null,
+   p_storage_path varchar(255),
+   p_title varchar(255) not null,
+   p_description mediumtext,
+   p_content mediumtext,
+   p_signature bigint not null default 0,
+   p_business_path varchar(255) not null,
+   fk_author_id bigint not null,
+   primary key (id)
+);
 
 create table o_pf_page_part (
    id bigint not null auto_increment,
@@ -1654,11 +1666,11 @@ create table o_pf_page_part (
    pos bigint default null,
    dtype varchar(32),
    p_content mediumtext,
+   fk_media_id bigint,
    fk_page_body_id bigint,
    primary key (id)
 );
 
-
 create table o_pf_category (
    id bigint not null auto_increment,
    creationdate datetime not null,
@@ -1666,8 +1678,6 @@ create table o_pf_category (
    primary key (id)
 );
 
-
-
 create table o_pf_category_relation (
    id bigint not null auto_increment,
    creationdate datetime not null,
@@ -1677,11 +1687,7 @@ create table o_pf_category_relation (
    primary key (id)
 );
 
-
-
-
-
-
+-- lti
 create table o_lti_outcome (
    id bigint not null,
    creationdate datetime not null,
@@ -2105,6 +2111,7 @@ alter table o_goto_registrant ENGINE = InnoDB;
 alter table o_vid_transcoding ENGINE = InnoDB;
 alter table o_pf_category_relation ENGINE = InnoDB;
 alter table o_pf_category ENGINE = InnoDB;
+alter table o_pf_media ENGINE = InnoDB;
 alter table o_pf_page_part ENGINE = InnoDB;
 alter table o_pf_section ENGINE = InnoDB;
 alter table o_pf_page_body ENGINE = InnoDB;
@@ -2472,7 +2479,11 @@ alter table o_pf_page add constraint pf_page_section_idx foreign key (fk_section
 
 alter table o_pf_page add constraint pf_page_body_idx foreign key (fk_body_id) references o_pf_page_body (id);
 
+alter table o_pf_media add constraint pf_media_author_idx foreign key (fk_author_id) references o_bs_identity (id);
+create index idx_category_rel_resid_idx on o_pf_media (p_business_path);
+
 alter table o_pf_page_part add constraint pf_page_page_body_idx foreign key (fk_page_body_id) references o_pf_page_body (id);
+alter table o_pf_page_part add constraint pf_page_media_idx foreign key (fk_media_id) references o_pf_media (id);
 
 create index idx_category_name_idx on o_pf_category (p_name);
 
diff --git a/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql b/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql
index 3bb549ecb4bfd8a4e172021db4cb953400013d18..a1de946280e5adce4236255c6b3b5d2d59bad8d3 100644
--- a/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql
+++ b/src/main/resources/database/postgresql/alter_10_x_0_to_11_0_0.sql
@@ -211,12 +211,34 @@ create table o_pf_page_part (
    pos int8 default null,
    dtype varchar(32),
    p_content text,
+   fk_media_id int8,
    fk_page_body_id int8,
    primary key (id)
 );
 
 alter table o_pf_page_part add constraint pf_page_page_body_idx foreign key (fk_page_body_id) references o_pf_page_body (id);
 create index idx_pf_page_page_body_idx on o_pf_page_part (fk_page_body_id);
+alter table o_pf_page_part add constraint pf_page_media_idx foreign key (fk_media_id) references o_pf_media (id);
+create index idx_pf_page_media_idx on o_pf_page_part (fk_media_id);
+
+create table o_pf_media (
+   id bigserial,
+   creationdate timestamp not null,
+   p_collection_date timestamp not null,
+   p_type varchar(64) not null,
+   p_storage_path varchar(255),
+   p_title varchar(255) not null,
+   p_description text,
+   p_content text,
+   p_signature int8 not null default 0,
+   p_business_path varchar(255) not null,
+   fk_author_id int8 not null,
+   primary key (id)
+);
+
+alter table o_pf_media add constraint pf_media_author_idx foreign key (fk_author_id) references o_bs_identity (id);
+create index idx_pf_media_author_idx on o_pf_media (fk_author_id);
+create index idx_media_storage_path_idx on o_pf_media (p_business_path);
 
 
 create table o_pf_category (
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index 4193afac0e22ec586945f26e91c0c6510e04a3f5..ade89b3b4df49682aba24fa9b7eadb325e946221 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1533,10 +1533,26 @@ create table o_pf_page_part (
    pos int8 default null,
    dtype varchar(32),
    p_content text,
+   fk_media_id int8,
    fk_page_body_id int8,
    primary key (id)
 );
 
+create table o_pf_media (
+   id bigserial,
+   creationdate timestamp not null,
+   p_collection_date timestamp not null,
+   p_type varchar(64) not null,
+   p_storage_path varchar(255),
+   p_title varchar(255) not null,
+   p_description text,
+   p_content text,
+   p_signature int8 not null default 0,
+   p_business_path varchar(255) not null,
+   fk_author_id int8 not null,
+   primary key (id)
+);
+
 create table o_pf_category (
    id bigserial,
    creationdate timestamp not null,
@@ -2480,6 +2496,12 @@ create index idx_pf_page_body_idx on o_pf_page (fk_body_id);
 
 alter table o_pf_page_part add constraint pf_page_page_body_idx foreign key (fk_page_body_id) references o_pf_page_body (id);
 create index idx_pf_page_page_body_idx on o_pf_page_part (fk_page_body_id);
+alter table o_pf_page_part add constraint pf_page_media_idx foreign key (fk_media_id) references o_pf_media (id);
+create index idx_pf_page_media_idx on o_pf_page_part (fk_media_id);
+
+alter table o_pf_media add constraint pf_media_author_idx foreign key (fk_author_id) references o_bs_identity (id);
+create index idx_pf_media_author_idx on o_pf_media (fk_author_id);
+create index idx_media_storage_path_idx on o_pf_media (p_business_path);
 
 create index idx_category_name_idx on o_pf_category (p_name);
 
diff --git a/src/test/java/org/olat/modules/portfolio/manager/MediaDAOTest.java b/src/test/java/org/olat/modules/portfolio/manager/MediaDAOTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a1b31f31650bbd0ea1951a3d8ebf3d79112c0311
--- /dev/null
+++ b/src/test/java/org/olat/modules/portfolio/manager/MediaDAOTest.java
@@ -0,0 +1,66 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.manager;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.id.Identity;
+import org.olat.modules.portfolio.Media;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 17.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MediaDAOTest extends OlatTestCase {
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private MediaDAO mediaDao;
+	
+	@Test
+	public void createMedia() {
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("pf-media-1");
+		Media media = mediaDao.createMedia("Media", "Media description", "Media content", "Forum", "[Media:0]", 10, id);
+		dbInstance.commit();
+		
+		Assert.assertNotNull(media);
+		Assert.assertNotNull(media.getKey());
+		Assert.assertNotNull(media.getCreationDate());
+		Assert.assertNotNull(media.getCollectionDate());
+		Assert.assertEquals(id, media.getAuthor());
+		
+		Media reloadedMedia = mediaDao.loadByKey(media.getKey());
+		Assert.assertNotNull(reloadedMedia);
+		Assert.assertEquals(media, reloadedMedia);
+		Assert.assertEquals(id, reloadedMedia.getAuthor());
+		Assert.assertEquals("Media", reloadedMedia.getTitle());
+		Assert.assertEquals("Media description", reloadedMedia.getDescription());
+		Assert.assertEquals("[Media:0]", reloadedMedia.getBusinessPath());
+		Assert.assertEquals(id, reloadedMedia.getAuthor());
+	}
+
+}
diff --git a/src/test/java/org/olat/selenium/PortfolioTest.java b/src/test/java/org/olat/selenium/PortfolioTest.java
index 6068c4e4c12655232234eabff70973929e0a5924..db70fbd2689c74e3449c3fce72bd81bfd8e36881 100644
--- a/src/test/java/org/olat/selenium/PortfolioTest.java
+++ b/src/test/java/org/olat/selenium/PortfolioTest.java
@@ -23,6 +23,8 @@ import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.UUID;
 
 import org.jboss.arquillian.container.test.api.Deployment;
@@ -58,13 +60,22 @@ import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.firefox.FirefoxDriver;
 
-
+/**
+ * 
+ * Suite of test for the e-Portfolio version 1.0
+ * 
+ * Initial date: 20.06.2016<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
 @RunWith(Arquillian.class)
 public class PortfolioTest {
 	
 	@Deployment(testable = false)
 	public static WebArchive createDeployment() {
-		return ArquillianDeployments.createDeployment();
+		Map<String,String> propertyPortfolioV1 = new HashMap<>();
+		propertyPortfolioV1.put("portfoliov2.enabled", "false");
+		return ArquillianDeployments.createDeployment(propertyPortfolioV1);
 	}
 
 	@Drone
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index 47c3141a931eef663337b9cf152ed0e18598b263..7ff15aca7cb145e830a7618e06eba1ef6bb9f814 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -155,6 +155,9 @@ import org.junit.runners.Suite;
 	org.olat.modules.gotomeeting.manager.GoToRegistrantDAOTest.class,
 	org.olat.modules.gotomeeting.GoToTimezoneIDsTest.class,
 	org.olat.modules.portfolio.manager.BinderDAOTest.class,
+	org.olat.modules.portfolio.manager.CategoryDAOTest.class,
+	org.olat.modules.portfolio.manager.MediaDAOTest.class,
+	org.olat.modules.portfolio.manager.PageDAOTest.class,
 	org.olat.modules.portfolio.manager.PortfolioServiceTest.class,
 	org.olat.modules.reminder.ReminderModuleTest.class,
 	org.olat.modules.reminder.manager.ReminderDAOTest.class,
diff --git a/src/test/java/org/olat/test/ArquillianDeployments.java b/src/test/java/org/olat/test/ArquillianDeployments.java
index 4e8182139cca8a1a6d5ca1c1f36dc5b686334ada..91db31a743f4b8f75f8234d67f517c6b59ad4a7a 100644
--- a/src/test/java/org/olat/test/ArquillianDeployments.java
+++ b/src/test/java/org/olat/test/ArquillianDeployments.java
@@ -26,7 +26,9 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.StringWriter;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
 import org.jboss.shrinkwrap.api.ArchivePath;
@@ -47,13 +49,15 @@ public class ArquillianDeployments {
 	public static final String TEST_RSRC = "src/test/resources";
 	public static final String LIB_DIR   = "target/openolat-lms-11.0-SNAPSHOT/WEB-INF/lib";
 
-	
 	public static WebArchive createDeployment() {
-		return createDeployment("openolat.war");
+		return createDeployment("openolat.war", new HashMap<String,String>());
 	}
-		
+	
+	public static WebArchive createDeployment(Map<String,String> overrideProperties) {
+		return createDeployment("openolat.war", overrideProperties);
+	}	
 
-	public static WebArchive createDeployment(String name) {
+	public static WebArchive createDeployment(String name, Map<String,String> overrideProperties) {
 		WebArchive archive = ShrinkWrap.create(WebArchive.class, name);
 
 		addClasses(archive);
@@ -62,12 +66,12 @@ public class ArquillianDeployments {
 		addResourceRecursive(new File(MAIN_JAVA), null, new JavaResourcesFilter(), archive);
 		addResourceRecursive(new File(MAIN_RSRC), null, new AllFileFilter(), archive);
 		addWebResourceRecursive(new File(WEBAPP), "static", new StaticFileFilter(), archive);
-		addOlatLocalProperties(archive);
+		addOlatLocalProperties(archive, overrideProperties);
 		archive.setWebXML(new File(WEBINF_TOMCAT, "web.xml"));
 		return archive;
 	}
 	
-	public static WebArchive addOlatLocalProperties(WebArchive archive) {
+	public static WebArchive addOlatLocalProperties(WebArchive archive, Map<String,String> overrideProperties) {
 		String profile = System.getProperty("profile");
 		if(profile == null || profile.isEmpty()) {
 			profile = "mysql";
@@ -90,6 +94,10 @@ public class ArquillianDeployments {
 				updatedProperties.setProperty(name, replacedValue);
 			}
 			
+			for(Map.Entry<String, String> entryToOverride:overrideProperties.entrySet()) {
+				updatedProperties.setProperty(entryToOverride.getKey(), entryToOverride.getValue());
+			}
+			
 			StringWriter writer = new StringWriter();
 			updatedProperties.store(writer, "Replaced for Arquillian deployements");
 			propertiesAsset = new StringAsset(writer.toString());