diff --git a/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectContactAddForm.java b/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectContactAddForm.java
new file mode 100644
index 0000000..648ea03
--- /dev/null
+++ b/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectContactAddForm.java
@@ -0,0 +1,153 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.arsdigita.cms.contenttypes.ui;
+
+import com.arsdigita.bebop.FormProcessException;
+import com.arsdigita.bebop.Label;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.event.FormSubmissionListener;
+import com.arsdigita.bebop.event.PrintEvent;
+import com.arsdigita.bebop.event.PrintListener;
+import com.arsdigita.bebop.form.Option;
+import com.arsdigita.bebop.form.SingleSelect;
+import com.arsdigita.bebop.parameters.NotNullValidationListener;
+import com.arsdigita.bebop.parameters.ParameterModel;
+import com.arsdigita.bebop.parameters.StringParameter;
+import com.arsdigita.cms.ItemSelectionModel;
+import com.arsdigita.cms.ui.assets.AssetSearchWidget;
+import com.arsdigita.cms.ui.authoring.BasicItemForm;
+import com.arsdigita.globalization.GlobalizedMessage;
+import com.arsdigita.util.UncheckedWrapperException;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.libreccm.cdi.utils.CdiUtil;
+import org.librecms.CmsConstants;
+import org.librecms.assets.ContactableEntity;
+import org.scientificcms.contenttypes.sciproject.SciProjectConstants;
+
+import java.util.ResourceBundle;
+import java.util.TooManyListenersException;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class SciProjectContactAddForm
+ extends BasicItemForm
+ implements FormSubmissionListener {
+
+ private final static Logger LOGGER = LogManager
+ .getLogger(SciProjectContactAddForm.class);
+
+ private static final String CONTACT_TYPE = "SciProjectContactType";
+
+ private AssetSearchWidget searchWidget;
+
+ private final String SEARCH = "project_contact";
+
+ private ItemSelectionModel itemModel;
+
+ private SciProjectContactsStep editStep;
+
+ private Label selectedContactLabel;
+
+ public SciProjectContactAddForm(final ItemSelectionModel itemModel,
+ final SciProjectContactsStep editStep,
+ final StringParameter selectedLanguage) {
+
+ super("ContactEntryAddForm", itemModel, selectedLanguage);
+ this.itemModel = itemModel;
+ this.editStep = editStep;
+ addSubmissionListener(this);
+ }
+
+ @Override
+ protected void addWidgets() {
+
+ searchWidget = new AssetSearchWidget(SEARCH, ContactableEntity.class);
+ searchWidget.setLabel(new GlobalizedMessage(
+ "cms.contenttypes.ui.sciproject.contact.type",
+ SciProjectConstants.SCI_PROJECT_BUNDLE));
+ add(searchWidget);
+
+ selectedContactLabel = new Label();
+ add(selectedContactLabel);
+
+ final ParameterModel contactTypeParam
+ = new StringParameter(CONTACT_TYPE);
+ final SingleSelect contactType = new SingleSelect(contactTypeParam);
+ contactType.setLabel(new GlobalizedMessage(
+ "cms.contenttypes.ui.sciproject.contact.type",
+ SciProjectConstants.SCI_PROJECT_BUNDLE));
+ contactType.addValidationListener(new NotNullValidationListener());
+
+ try {
+
+ contactType.addPrintListener(new PrintListener() {
+
+ @Override
+ public void prepare(final PrintEvent event) {
+
+ final SingleSelect target = (SingleSelect) event.getTarget();
+ target.clearOptions();
+
+ target.addOption(new Option("",
+ new Label(new GlobalizedMessage(
+ "cms.ui.select_one",
+ CmsConstants.CMS_BUNDLE))));
+
+ final String contactTypeBundleName = getController()
+ .getContactTypesBundleName();
+ final ResourceBundle contactTypesBundle = ResourceBundle
+ .getBundle(contactTypeBundleName);
+ for (final String key : contactTypesBundle.keySet()) {
+
+ final Option option = new Option(
+ key,
+ new Label(
+ new GlobalizedMessage(key,
+ contactTypeBundleName)));
+ target.addOption(option);
+ }
+ }
+
+ });
+
+ } catch (TooManyListenersException ex) {
+ throw new UncheckedWrapperException(
+ "Something has gone terribly wrong", ex);
+ }
+ add(contactType);
+ }
+
+ @Override
+ public void init(final FormSectionEvent event) throws FormProcessException {
+
+ throw new UnsupportedOperationException("ToDo");
+ }
+
+ @Override
+ public void process(final FormSectionEvent event) throws
+ FormProcessException {
+
+ throw new UnsupportedOperationException("ToDo");
+ }
+
+ @Override
+ public void submitted(final FormSectionEvent event) throws
+ FormProcessException {
+
+ throw new UnsupportedOperationException("ToDo");
+ }
+
+ private SciProjectController getController() {
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+
+ return cdiUtil.findBean(SciProjectController.class);
+ }
+
+}
diff --git a/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectContactsStep.java b/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectContactsStep.java
new file mode 100644
index 0000000..b50f8b2
--- /dev/null
+++ b/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectContactsStep.java
@@ -0,0 +1,77 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.arsdigita.cms.contenttypes.ui;
+
+import com.arsdigita.bebop.parameters.StringParameter;
+import com.arsdigita.cms.ItemSelectionModel;
+import com.arsdigita.cms.ui.authoring.AuthoringKitWizard;
+import com.arsdigita.cms.ui.authoring.BasicItemForm;
+import com.arsdigita.cms.ui.authoring.SimpleEditStep;
+import com.arsdigita.cms.ui.workflow.WorkflowLockedComponentAccess;
+import com.arsdigita.globalization.GlobalizedMessage;
+
+import org.librecms.assets.ContactableEntity;
+import org.scientificcms.contenttypes.sciproject.SciProjectConstants;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class SciProjectContactsStep extends SimpleEditStep {
+
+ private ContactableEntity selectedContact;
+ private String selectedContactType;
+
+ public SciProjectContactsStep(final ItemSelectionModel itemModel,
+ final AuthoringKitWizard parent) {
+ this(itemModel, parent, null);
+ }
+
+ public SciProjectContactsStep(final ItemSelectionModel itemModel,
+ final AuthoringKitWizard parent,
+ final StringParameter selectedLanguageParam) {
+ super(itemModel, parent, selectedLanguageParam);
+ }
+
+ public SciProjectContactsStep(final ItemSelectionModel itemModel,
+ final AuthoringKitWizard parent,
+ final String parameterSuffix,
+ final StringParameter selectedLanguageParam) {
+ super(itemModel, parent, selectedLanguageParam, parameterSuffix);
+
+ final BasicItemForm addContactSheet = new SciProjectContactAddForm(
+ itemModel, this);
+
+ add(SciProjectUiConstants.ADD_CONTACT_SHEET_NAME,
+ new GlobalizedMessage(
+ "cms.contenttypes.ui.genericorgaunit.add_contact",
+ SciProjectConstants.SCI_PROJECT_BUNDLE),
+ new WorkflowLockedComponentAccess(addContactSheet, itemModel),
+ addContactSheet.getSaveCancelSection().getCancelButton());
+
+ final SciProjectContactsTable contactsTable
+ = new SciProjectContactsTable(itemModel, this);
+ setDisplayComponent(contactsTable);
+ }
+
+ public ContactableEntity getSelectedContact() {
+ return selectedContact;
+ }
+
+ public void setSelectedContact(final ContactableEntity selectedContact) {
+ this.selectedContact = selectedContact;
+ }
+
+ public String getSelectedContactType() {
+ return selectedContactType;
+ }
+
+ public void setSelectedContactType(final String selectedContactType) {
+ this.selectedContactType = selectedContactType;
+ }
+}
+
+}
diff --git a/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectController.java b/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectController.java
new file mode 100644
index 0000000..f60dfe8
--- /dev/null
+++ b/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectController.java
@@ -0,0 +1,71 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.arsdigita.cms.contenttypes.ui;
+
+import org.libreccm.configuration.ConfigurationManager;
+import org.scientificcms.contenttypes.sciproject.SciProject;
+import org.scientificcms.contenttypes.sciproject.SciProjectConfig;
+import org.scientificcms.contenttypes.sciproject.SciProjectRepository;
+
+import java.time.LocalDate;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.transaction.Transactional;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@RequestScoped
+class SciProjectController {
+
+ @Inject
+ private ConfigurationManager confManager;
+
+ @Inject
+ private SciProjectRepository projectRepository;
+
+ public String getContactTypesBundleName() {
+
+ final SciProjectConfig conf = confManager
+ .findConfiguration(SciProjectConfig.class);
+
+ return conf.getContactTypesBundleName();
+ }
+
+ @Transactional(Transactional.TxType.REQUIRED)
+ public void save(final long projectId,
+ final Locale selectedLocale,
+ final Map data) {
+
+ final SciProject project = projectRepository
+ .findById(projectId, SciProject.class)
+ .orElseThrow(
+ () -> new IllegalArgumentException(
+ String.format("No SciProject with ID %d found.",
+ projectId))
+ );
+
+ final Date begin = (Date) data.get(SciProjectUiConstants.BEGIN);
+ final Date end = (Date) data.get(SciProjectUiConstants.END);
+ final String shortDesc = (String) data
+ .get(SciProjectUiConstants.PROJECT_SHORT_DESCRIPTION);
+
+ final LocalDate beginDate = LocalDate.from(begin.toInstant());
+ final LocalDate endDate = LocalDate.from(end.toInstant());
+
+ project.setBegin(beginDate);
+ project.setEnd(endDate);
+ project.getShortDescription().addValue(selectedLocale, shortDesc);
+
+ projectRepository.save(project);
+ }
+
+}
diff --git a/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectPropertyForm.java b/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectPropertyForm.java
new file mode 100644
index 0000000..9e9adf9
--- /dev/null
+++ b/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectPropertyForm.java
@@ -0,0 +1,141 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.arsdigita.cms.contenttypes.ui;
+
+import com.arsdigita.bebop.FormData;
+import com.arsdigita.bebop.FormProcessException;
+import com.arsdigita.bebop.PageState;
+import com.arsdigita.bebop.event.FormInitListener;
+import com.arsdigita.bebop.event.FormProcessListener;
+import com.arsdigita.bebop.event.FormSectionEvent;
+import com.arsdigita.bebop.event.FormSubmissionListener;
+import com.arsdigita.bebop.form.Date;
+import com.arsdigita.bebop.parameters.DateParameter;
+import com.arsdigita.bebop.parameters.StringParameter;
+import com.arsdigita.cms.ItemSelectionModel;
+import com.arsdigita.cms.ui.authoring.BasicPageForm;
+import com.arsdigita.cms.ui.authoring.SelectedLanguageUtil;
+import com.arsdigita.globalization.GlobalizedMessage;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.libreccm.cdi.utils.CdiUtil;
+import org.scientificcms.contenttypes.sciproject.SciProject;
+import org.scientificcms.contenttypes.sciproject.SciProjectConstants;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public class SciProjectPropertyForm
+ extends BasicPageForm
+ implements FormProcessListener, FormInitListener, FormSubmissionListener {
+
+ private static final Logger LOGGER = LogManager
+ .getLogger(SciProjectPropertyForm.class);
+
+ public static final String ID = "SciProject_edit";
+
+ private SciProjectPropertiesStep step;
+
+ private final StringParameter selectedLanguageParameter;
+
+ public SciProjectPropertyForm(
+ final ItemSelectionModel itemModel,
+ final StringParameter selectedLanguageParameter) {
+
+ this(itemModel, null, selectedLanguageParameter);
+ }
+
+ public SciProjectPropertyForm(
+ final ItemSelectionModel itemModel,
+ final SciProjectPropertiesStep step,
+ final StringParameter selectedLanguageParameter) {
+ super(ID, itemModel, selectedLanguageParameter);
+ this.step = step;
+ this.selectedLanguageParameter = selectedLanguageParameter;
+ addSubmissionListener(this);
+ }
+
+ @Override
+ protected void addWidgets() {
+
+ super.addWidgets();
+
+ final DateParameter beginParam = new DateParameter(
+ SciProjectUiConstants.BEGIN);
+ final Date begin = new Date(beginParam);
+ begin.setLabel(new GlobalizedMessage(
+ "sciproject.ui.begin", SciProjectConstants.SCI_PROJECT_BUNDLE));
+
+ final DateParameter endParam = new DateParameter(
+ SciProjectUiConstants.END);
+ final Date end = new Date(endParam);
+
+ throw new UnsupportedOperationException("ToDo");
+ }
+
+ @Override
+ public void init(final FormSectionEvent event) throws FormProcessException {
+
+ final FormData data = event.getFormData();
+ final SciProject project = (SciProject) super.initBasicWidgets(event);
+
+ throw new UnsupportedOperationException("ToDo");
+
+ }
+
+ @Override
+ public void process(final FormSectionEvent event)
+ throws FormProcessException {
+
+ final PageState state = event.getPageState();
+ final FormData formData = event.getFormData();
+
+ final SciProject project = (SciProject) super
+ .processBasicWidgets(event);
+
+ if (project != null
+ && getSaveCancelSection().getSaveButton().isSelected(state)) {
+
+ final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
+ final SciProjectController controller = cdiUtil
+ .findBean(SciProjectController.class);
+
+ final Map data = new HashMap<>();
+ data.put(SciProjectUiConstants.BEGIN,
+ formData.get(SciProjectUiConstants.BEGIN));
+ data.put(SciProjectUiConstants.END,
+ formData.get(SciProjectUiConstants.END));
+ data.put(
+ SciProjectUiConstants.PROJECT_SHORT_DESCRIPTION,
+ formData.get(SciProjectUiConstants.PROJECT_SHORT_DESCRIPTION));
+
+ final Locale selectedLangauge = SelectedLanguageUtil
+ .selectedLocale(state, selectedLanguageParameter);
+
+ controller.save(project.getObjectId(), selectedLangauge, data);
+ }
+ }
+
+ @Override
+ public void submitted(final FormSectionEvent event)
+ throws FormProcessException {
+
+ final PageState state = event.getPageState();
+
+ if (step != null
+ && getSaveCancelSection().getCancelButton().isSelected(state)) {
+
+ step.cancelStreamlinedCreation(state);
+ }
+ }
+
+}
diff --git a/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectUiConstants.java b/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectUiConstants.java
new file mode 100644
index 0000000..0cbb3ac
--- /dev/null
+++ b/sci-types-project/src/main/java/com/arsdigita/cms/contenttypes/ui/SciProjectUiConstants.java
@@ -0,0 +1,32 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.arsdigita.cms.contenttypes.ui;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public final class SciProjectUiConstants {
+
+ public static final String ADD_CONTACT_SHEET_NAME = "addContact";
+
+ public static final String BEGIN = "begin";
+
+ public static final String EDIT_SHEET_NAME = "edit";
+
+ public static final String END = "end";
+
+ public static final String NAME = "name";
+
+ public static final String PROJECT_SHORT_DESCRIPTION = "shortDescription";
+
+ public static final String TITLE = "title";
+
+ private SciProjectUiConstants() {
+ // Nothing
+ }
+
+}
diff --git a/sci-types-project/src/main/java/org/scientificcms/contenttypes/sciproject/SciProjectConfig.java b/sci-types-project/src/main/java/org/scientificcms/contenttypes/sciproject/SciProjectConfig.java
new file mode 100644
index 0000000..18da32c
--- /dev/null
+++ b/sci-types-project/src/main/java/org/scientificcms/contenttypes/sciproject/SciProjectConfig.java
@@ -0,0 +1,42 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.scientificcms.contenttypes.sciproject;
+
+import org.libreccm.cdi.utils.CdiUtil;
+import org.libreccm.configuration.Configuration;
+import org.libreccm.configuration.ConfigurationManager;
+import org.libreccm.configuration.Setting;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+@Configuration
+public class SciProjectConfig {
+
+ @Setting()
+ private String contactTypesBundleName
+ = "org.scientificcms.contenttypes.sciproject.DefaultContactTypes";
+
+ public static SciProjectConfig getConfig() {
+ final ConfigurationManager confManager = CdiUtil.createCdiUtil()
+ .findBean(ConfigurationManager.class);
+ return confManager.findConfiguration(SciProjectConfig.class);
+ }
+
+ public SciProjectConfig() {
+ super();
+ }
+
+ public String getContactTypesBundleName() {
+ return contactTypesBundleName;
+ }
+
+ public void setContactTypesBundleName(final String contactTypesBundle) {
+ this.contactTypesBundleName = contactTypesBundle;
+ }
+
+}
diff --git a/sci-types-project/src/main/resources/org/scientificcms/contenttypes/sciproject/DefaultContactTypes.properties b/sci-types-project/src/main/resources/org/scientificcms/contenttypes/sciproject/DefaultContactTypes.properties
new file mode 100644
index 0000000..e72b04d
--- /dev/null
+++ b/sci-types-project/src/main/resources/org/scientificcms/contenttypes/sciproject/DefaultContactTypes.properties
@@ -0,0 +1 @@
+sciproject.contact=Contact
diff --git a/sci-types-project/src/main/resources/org/scientificcms/contenttypes/sciproject/DefaultContactTypes_de.properties b/sci-types-project/src/main/resources/org/scientificcms/contenttypes/sciproject/DefaultContactTypes_de.properties
new file mode 100644
index 0000000..aaf69df
--- /dev/null
+++ b/sci-types-project/src/main/resources/org/scientificcms/contenttypes/sciproject/DefaultContactTypes_de.properties
@@ -0,0 +1 @@
+sciproject.contact=Kontakt
diff --git a/sci-types-project/src/test/java/org/libreccm/security/SecurityEntitiesPrefabProvider.java b/sci-types-project/src/test/java/org/libreccm/security/SecurityEntitiesPrefabProvider.java
new file mode 100644
index 0000000..c4f826c
--- /dev/null
+++ b/sci-types-project/src/test/java/org/libreccm/security/SecurityEntitiesPrefabProvider.java
@@ -0,0 +1,53 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.libreccm.security;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+/**
+ *
+ * @author Jens Pelzetter
+ */
+public final class SecurityEntitiesPrefabProvider {
+
+ private SecurityEntitiesPrefabProvider() {
+ // Nothing
+ }
+
+ public static void addPrefabEntities(final EqualsVerifier> verifier) {
+
+ final Role role1 = new Role();
+ role1.setRoleId(2001);
+ role1.setName("role1");
+
+ final Role role2 = new Role();
+ role2.setRoleId(2002);
+ role2.setName("role2");
+
+ verifier.withPrefabValues(Role.class, role1, role2);
+
+ final Group group1 = new Group();
+ group1.setPartyId(3001);
+ group1.setName("group1");
+
+ final Group group2 = new Group();
+ group2.setPartyId(3002);
+ group2.setName("group2");
+
+ verifier.withPrefabValues(Group.class, group1, group2);
+
+ final User user1 = new User();
+ user1.setPartyId(4001);
+ user1.setName("user1");
+
+ final User user2 = new User();
+ user2.setPartyId(4002);
+ user2.setName("user2");
+
+ verifier.withPrefabValues(User.class, user1, user2);
+ }
+
+}