diff --git a/Automation/src/test/java/Constants.java b/Automation/src/test/java/Constants.java
index efd77bf67facffb38475024187eb57a86cde2e59..eb6c8404b0ab402799ef0c44e580b4c051178a53 100644
--- a/Automation/src/test/java/Constants.java
+++ b/Automation/src/test/java/Constants.java
@@ -1,11 +1,29 @@
+import org.apache.commons.lang3.RandomStringUtils;
+
 public class Constants {
-    public static final String URL = "http://ec2co-ecsel-m3gy9h288kzs-2054883442.eu-west-1.elb.amazonaws.com/";
+    public static final String URL = "http://qa.review.hindawi.com";
     public static final String email = "adrian.onofrei+";
-    public static final String firstname = "Test FN";
-    public static final String lastname = "test LN";
+    public static final String firstname = "Test Author";
+    public static final String lastname = "Test Author";
     public static final String affiliation = "TS affiliation";
-    public static final String password = "Testing123";
+    public static final String password = "password";
     public static final String adminEmail = "admin";
     public static final String adminPass = "password";
+    public static final String randomStr = RandomStringUtils.randomAlphabetic(4);
+    public static final String firstnameHE = "Test HE";
+    public static final String lastnameHE = "Test HE";
+    public static final String passwordHE = "Testing123";
+    public static final String emailHE = "adrian.onofrei+HE";
+    public static final String affiliationHE = "TS HE affiliation";
+    public static final String manusName = RandomStringUtils.randomAlphabetic(16);
+    public static final String manusAbstract = RandomStringUtils.randomAlphabetic(16);
+    public static final String fileManuscript = "/Users/adionofrei/Documents/Manuscript.pdf";
+    public static final String fileSupplementary = "/Users/adionofrei/Documents/Manuscript.pdf";
+    public static final String fileCoverLetter = "/Users/adionofrei/Documents/Manuscript.pdf";
+
+
+    public static String uidAuth = null;
+    public static String uidHE = null;
+
 
 }
diff --git a/Automation/src/test/java/CreateAccounts.java b/Automation/src/test/java/CreateAccounts.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8b5fca1fdd64bc0008eb314627e10ee0c6dcb76
--- /dev/null
+++ b/Automation/src/test/java/CreateAccounts.java
@@ -0,0 +1,179 @@
+import io.restassured.path.json.JsonPath;
+import org.junit.*;
+import org.openqa.selenium.*;
+import org.openqa.selenium.remote.DesiredCapabilities;
+import org.openqa.selenium.remote.RemoteWebDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import static org.junit.Assert.*;
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+import io.restassured.specification.RequestSpecification;
+import org.json.simple.JSONObject;
+import java.net.URL;
+
+
+public class CreateAccounts {
+
+    private static WebDriver driver = null;
+    private static WebDriverWait wait = null;
+    public String URL = Constants.URL;
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws Exception {
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        //driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.firefox());
+        driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.chrome());
+        //driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
+        wait = new WebDriverWait(driver, 10);
+        String window = driver.getWindowHandle();
+        ((JavascriptExecutor) driver).executeScript("alert('Test')");
+        driver.switchTo().alert().accept();
+        driver.switchTo().window(window);
+        Utils.disableWarning();
+    }
+
+
+    @After
+    public void tearDown() {
+        driver.quit();
+    }
+
+    @Test
+    public void createNewAuthor() throws Exception {
+
+        Utils.createAuthor(driver,wait, URL, Constants.randomStr, Constants.firstname, Constants.lastname, Constants.affiliation, Constants.email + Constants.randomStr + "@thinslices.com",Constants.password);
+
+
+        try {
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='new-manuscript']")));
+        } catch (NoSuchElementException e) {
+            System.out.println(e.toString());
+        }
+
+        WebElement element = driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[1]/div[1]/div[2]/div/span[2]"));
+        String username = element.getText();
+
+        assertEquals(Constants.firstname+Constants.randomStr, username);
+
+        RestAssured.baseURI = URL;
+
+        //Get user token after login with new account
+
+        RequestSpecification request = RestAssured.given().header("Content-Type", "application/json");
+
+        JSONObject requestParams = new JSONObject();
+        requestParams.put("username", Constants.email + Constants.randomStr + "@thinslices.com");
+        requestParams.put("password",  Constants.password);
+        request.body(requestParams.toJSONString());
+        Response response = request.post("api/users/authenticate");
+
+        JsonPath jsonPathEvaluator = response.body().jsonPath();
+        String token = jsonPathEvaluator.get("token");
+
+        //Get user ID and confirmationToken
+
+        RequestSpecification requestUid = RestAssured.given().header("Authorization", "Bearer " + token);
+        Response responseUid = requestUid.get("api/users/authenticate");
+        JsonPath jsonPathEvaluatorUid = responseUid.body().jsonPath();
+
+        String confirmationToken = jsonPathEvaluatorUid.get("confirmationToken");
+
+        Constants.uidAuth = jsonPathEvaluatorUid.get("id");
+
+        //Activate user
+
+        driver.get(URL + "confirm-signup?userId=" + Constants.uidAuth + "&confirmationToken=" + confirmationToken);
+
+        try {
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//button[contains(text(),'" + "Go to Dashboard" + "')]")));
+        } catch (NoSuchElementException e) {
+            System.out.println(e.toString());
+        }
+
+        assertEquals("Your account has been successfully confirmed. Welcome to Hindawi!", driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[2]/div/div")).getText());
+    }
+
+    @Test
+    public void createNewHE() throws Exception {
+
+        Utils.createAuthor(driver,wait, URL, Constants.randomStr, Constants.firstnameHE, Constants.lastnameHE, Constants.affiliationHE, Constants.emailHE + Constants.randomStr + "@thinslices.com",Constants.passwordHE);
+
+
+        try {
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='new-manuscript']")));
+        } catch (NoSuchElementException e) {
+            System.out.println(e.toString());
+        }
+
+        WebElement element = driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[1]/div[1]/div[2]/div/span[2]"));
+        String username = element.getText();
+
+        assertEquals(Constants.firstnameHE + Constants.randomStr, username);
+
+        RestAssured.baseURI = URL;
+
+        //Get user token after login with new account
+
+        RequestSpecification request = RestAssured.given().header("Content-Type", "application/json");
+
+        JSONObject requestParams = new JSONObject();
+        requestParams.put("username", Constants.emailHE + Constants.randomStr + "@thinslices.com");
+        requestParams.put("password",  Constants.passwordHE);
+        request.body(requestParams.toJSONString());
+        Response response = request.post("api/users/authenticate");
+
+        JsonPath jsonPathEvaluator = response.body().jsonPath();
+        String token = jsonPathEvaluator.get("token");
+
+        //Get user ID and confirmationToken
+
+        RequestSpecification requestUid = RestAssured.given().header("Authorization", "Bearer " + token);
+        Response responseUid = requestUid.get("api/users/authenticate");
+        JsonPath jsonPathEvaluatorUid = responseUid.body().jsonPath();
+
+        String confirmationToken = jsonPathEvaluatorUid.get("confirmationToken");
+        Constants.uidHE = jsonPathEvaluatorUid.get("id");
+
+        //Activate user
+
+        driver.get(URL + "confirm-signup?userId=" + Constants.uidHE + "&confirmationToken=" + confirmationToken);
+
+        try {
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//button[contains(text(),'" + "Go to Dashboard" + "')]")));
+        } catch (NoSuchElementException e) {
+            System.out.println(e.toString());
+        }
+
+        assertEquals("Your account has been successfully confirmed. Welcome to Hindawi!", driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[2]/div/div")).getText());
+
+        driver.get(URL+"login?next=/");
+        Utils.validLogin( driver,  wait,  URL, Constants.adminEmail, Constants.adminPass);
+        driver.get(URL + "admin/users/edit/" + Constants.uidHE);
+
+        try {
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//button[contains(text(),'" + "Save user" + "')]")));
+        } catch (NoSuchElementException e) {
+            System.out.println(e.toString());
+        }
+
+        driver.findElement(By.cssSelector("input[name=handlingEditor] + span")).click();
+        driver.findElement(By.cssSelector("button[type=submit]")).click();
+
+        try {
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='button-add-user']")));
+        } catch (NoSuchElementException e) {
+            System.out.println(e.toString());
+        }
+
+        assertEquals(URL + "admin/users", driver.getCurrentUrl() );
+        assertEquals("  Add User", driver.findElement(By.cssSelector("button[data-test='button-add-user']")).getText());
+    }
+}
diff --git a/Automation/src/test/java/CreateAuthor.java b/Automation/src/test/java/CreateAuthor.java
deleted file mode 100644
index 065b1e9293836ec8c850debbbb240876f80fe07f..0000000000000000000000000000000000000000
--- a/Automation/src/test/java/CreateAuthor.java
+++ /dev/null
@@ -1,104 +0,0 @@
-import io.restassured.path.json.JsonPath;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.junit.*;
-import org.openqa.selenium.*;
-import org.openqa.selenium.remote.DesiredCapabilities;
-import org.openqa.selenium.remote.RemoteWebDriver;
-import org.openqa.selenium.support.ui.ExpectedConditions;
-import org.openqa.selenium.support.ui.WebDriverWait;
-import static org.junit.Assert.*;
-import io.restassured.RestAssured;
-import io.restassured.response.Response;
-import io.restassured.specification.RequestSpecification;
-import org.json.simple.JSONObject;
-import java.net.URL;
-
-
-public class CreateAuthor {
-
-    private static WebDriver driver = null;
-    private static WebDriverWait wait = null;
-    public String URL = Constants.URL;
-
-    @BeforeClass
-    public static void setUpClass() throws Exception {
-    }
-
-    @AfterClass
-    public static void tearDownClass() throws Exception {
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        //driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.firefox());
-        driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.chrome());
-        //driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
-        wait = new WebDriverWait(driver, 10);
-        String window = driver.getWindowHandle();
-        ((JavascriptExecutor) driver).executeScript("alert('Test')");
-        driver.switchTo().alert().accept();
-        driver.switchTo().window(window);
-        Utils.disableWarning();
-    }
-
-
-    @After
-    public void tearDown() {
-        driver.quit();
-    }
-
-    @Test
-    public void createNewAuthor() throws Exception {
-
-        String s = RandomStringUtils.randomAlphabetic(8);
-        Utils.createAuthor(driver,wait, URL, s, Constants.firstname, Constants.lastname, Constants.affiliation, Constants.email+s+"@thinslices.com",Constants.password);
-
-
-        try {
-            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='new-manuscript']")));
-        } catch (NoSuchElementException e) {
-            System.out.println(e.toString());
-        }
-
-        WebElement element = driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[1]/div[1]/div[2]/div/span[2]"));
-        String username = element.getText();
-
-        assertEquals(Constants.firstname+s, username);
-
-        RestAssured.baseURI = URL;
-
-        //Get user token after login with new account
-
-        RequestSpecification request = RestAssured.given().header("Content-Type", "application/json");
-
-        JSONObject requestParams = new JSONObject();
-        requestParams.put("username", Constants.email+s+"@thinslices.com");
-        requestParams.put("password",  Constants.password);
-        request.body(requestParams.toJSONString());
-        Response response = request.post("api/users/authenticate");
-
-        JsonPath jsonPathEvaluator = response.body().jsonPath();
-        String token = jsonPathEvaluator.get("token");
-
-        //Get user ID and confimationToken
-
-        RequestSpecification requestUid = RestAssured.given().header("Authorization", "Bearer "+token);
-        Response responseUid = requestUid.get("api/users/authenticate");
-        JsonPath jsonPathEvaluatorUid = responseUid.body().jsonPath();
-
-        String confirmationToken = jsonPathEvaluatorUid.get("confirmationToken");
-        String uid = jsonPathEvaluatorUid.get("id");
-
-        //Activate user
-
-        driver.get(URL+"confirm-signup?userId="+uid+"&confirmationToken="+confirmationToken);
-
-        try {
-            wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(".//button[contains(text(),'"+"Go to Dashboard"+"')]")));
-        } catch (NoSuchElementException e) {
-            System.out.println(e.toString());
-        }
-
-        assertEquals("Your account has been successfully confirmed. Welcome to Hindawi!", driver.findElement(By.xpath("//*[@id=\"root\"]/div/div/div[2]/div/div")).getText());
-    }
-}
diff --git a/Automation/src/test/java/ManuscriptFlow.java b/Automation/src/test/java/ManuscriptFlow.java
new file mode 100644
index 0000000000000000000000000000000000000000..db5c49a8195c8c125f5c3e817dabf4eef76a07bb
--- /dev/null
+++ b/Automation/src/test/java/ManuscriptFlow.java
@@ -0,0 +1,155 @@
+import io.restassured.RestAssured;
+import io.restassured.path.json.JsonPath;
+import io.restassured.response.Response;
+import io.restassured.specification.RequestSpecification;
+import org.json.simple.JSONObject;
+import org.junit.*;
+import org.openqa.selenium.*;
+import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.remote.DesiredCapabilities;
+import org.openqa.selenium.remote.RemoteWebDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.Select;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.net.URL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class ManuscriptFlow {
+    private static WebDriver driver = null;
+    private static WebDriverWait wait = null;
+    public String URL = Constants.URL;
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws Exception {
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        //driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.firefox());
+        driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"), DesiredCapabilities.chrome());
+        //driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
+        wait = new WebDriverWait(driver, 10);
+        String window = driver.getWindowHandle();
+        ((JavascriptExecutor) driver).executeScript("alert('Test')");
+        driver.switchTo().alert().accept();
+        driver.switchTo().window(window);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        //driver.quit();
+    }
+
+    @Test
+    public void manuscriptFlow() throws Exception {
+        /* Add constants.random after testing this function separably */
+        Utils.validLogin( driver,  wait,  URL, Constants.email + /*Constants.randomStr*/ "auth1" + "@thinslices.com", Constants.password);
+
+        WebElement validLogin = null;
+
+        try {
+            validLogin = wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='new-manuscript']")));
+        } catch (NoSuchElementException e) {
+
+        }
+
+        assertNotNull(validLogin);
+
+        driver.findElement(By.cssSelector("button[data-test='new-manuscript']")).click();
+
+        try {
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='submission-next']")));
+        } catch (NoSuchElementException e) {
+
+        }
+
+        assertNotNull(driver.findElement(By.cssSelector("button[data-test='submission-next']")));
+
+        // First step submission flow
+        driver.findElement(By.cssSelector("[data-test-id='agree-checkbox']")).click();
+        driver.findElement(By.cssSelector("button[data-test='submission-next']")).click();
+
+        // Second step submission flow
+        try {
+             wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".wizard-step >[data-test-id='row']:nth-of-type(2) span")));
+        } catch (NoSuchElementException e) {
+
+        }
+
+        assertEquals("Please provide the details of all the authors of this manuscript, in the order that they appear on the manuscript. Your details have been prefilled as the submitting author.",driver.findElement(By.cssSelector(".wizard-step >[data-test-id='row']:nth-of-type(2) span")).getText());
+        assertEquals("MANUSCRIPT TITLE\n*", driver.findElement(By.cssSelector("[data-test-id='submission-title']")).getText());
+
+        driver.findElement(By.cssSelector("input[name='metadata.title']")).sendKeys(Constants.manusName);
+        driver.findElement(By.cssSelector("[data-test-id='submission-type']")).click();
+        try {
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("[data-test-id='submission-type'] div[role=\"option\"]")));
+        } catch (NoSuchElementException e) {
+
+        }
+        driver.findElement(By.cssSelector("[data-test-id='submission-type'] div[role=\"option\"]:nth-child(1)")).click();
+        driver.findElement(By.cssSelector("[data-test-id='submission-abstract'] textarea")).sendKeys(Constants.manusAbstract);
+        WebElement element = driver.findElement(By.cssSelector("[name='conflicts.hasConflicts'][value='no']"));
+
+        Utils.scrollToElement(driver, element);
+        element.click();
+
+        driver.findElement(By.cssSelector("[name='conflicts.hasDataAvailability'][value='yes']")).click();
+        WebElement element1 = driver.findElement(By.cssSelector("[name='conflicts.hasFunding'][value='yes']"));
+
+        Utils.scrollToElement(driver, element1);
+        element1.click();
+
+        WebElement element2 = driver.findElement(By.cssSelector("button[data-test='submission-next']"));
+
+        Utils.scrollToElement(driver, element2);
+        element2.click();
+
+        // Third step submission flow
+
+        try {
+            wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.cssSelector(".wizard-step [level='2']"))));
+        } catch (NoSuchElementException e) {
+
+        }
+        WebElement pageTitle = driver.findElement(By.cssSelector(".wizard-step [level='2']"));
+        assertEquals("3. Manuscript Files Upload", pageTitle.getText());
+
+        try {
+            wait.until(ExpectedConditions.visibilityOf(pageTitle));
+        } catch (NoSuchElementException e) {
+
+        }
+
+        driver.findElement(By.cssSelector(/*"[data-test='upload-manuscripts']*/"input[type=\"file\"]")).sendKeys(Constants.fileManuscript);
+//        driver.findElement(By.cssSelector("[data-test='upload-supplementary'] input[type=\"file\"]")).sendKeys(Constants.fileSupplementary);
+//        driver.findElement(By.cssSelector("[data-test='upload-coverLetter'] input[type=\"file\"]")).sendKeys(Constants.fileCoverLetter);
+
+        try {
+            wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("button[data-test='submission-next']")));
+        } catch (NoSuchElementException e) {
+
+        }
+
+        WebElement element3 = driver.findElement(By.cssSelector("button[data-test='submission-next']"));
+        Utils.scrollToElement(driver, element3);
+        element3.click();
+
+        driver.findElement(By.xpath("//button[contains(.,'AGREE & SUBMIT')]")).click();
+
+        try {
+            wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//button[contains(.,'GO TO DASHBOARD')]")));
+        } catch (NoSuchElementException e) {
+
+        }
+
+        driver.findElement(By.xpath("//button[contains(.,'GO TO DASHBOARD')]")).click();
+
+    }
+}
diff --git a/Automation/src/test/java/Utils.java b/Automation/src/test/java/Utils.java
index cc31dadae8f24c486d4c45c9d146d3543956b3f6..7d10e9b50dd5f7bb91ba721c06512cf1e28ecec9 100644
--- a/Automation/src/test/java/Utils.java
+++ b/Automation/src/test/java/Utils.java
@@ -85,5 +85,12 @@ public class Utils {
         driver.findElement(By.xpath(".//button[contains(text(),'"+"CONFIRM"+"')]")).click();
 
     }
+
+    public static void  scrollToElement(WebDriver driver, WebElement el) {
+        if (driver instanceof JavascriptExecutor) {
+            ((JavascriptExecutor) driver)
+                    .executeScript("arguments[0].scrollIntoView(true);", el);
+        }
+    }
 }
 
diff --git a/Dockerfile b/Dockerfile
index 8bb801c8bb952fb053dc6ab9ad5d719022819bd6..88b5a40e2e356674b3875599e610feece9c8c5cc 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -15,7 +15,6 @@ RUN [ "yarn", "cache", "clean"]
 RUN [ "rm", "-rf", "/npm-packages-offline-cache"]
 
 WORKDIR ${HOME}/packages/xpub-faraday
-
 ENV NODE_ENV "production"
 RUN echo $NODE_ENV
 
diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js
index e50d81e78664dd1caea593a658728fd21370c69a..fbfcf2db03ad8928dbf383f8b80c010fb256d2a0 100644
--- a/packages/component-faraday-selectors/src/index.js
+++ b/packages/component-faraday-selectors/src/index.js
@@ -174,4 +174,15 @@ export const pendingHEInvitation = (state, collectionId) =>
         i.role === 'handlingEditor' &&
         !i.hasAnswer,
     )
+
+const hideCustomIdStatuses = ['draft', 'technicalChecks']
+export const newestFirstParseCustomId = items =>
+  chain(items)
+    .orderBy(['created'], ['desc'])
+    .map(item => ({
+      ...item,
+      customId:
+        !hideCustomIdStatuses.includes(get(item, 'status', 'draft')) &&
+        item.customId,
+    }))
     .value()
diff --git a/packages/component-faraday-ui/src/ManuscriptCard.js b/packages/component-faraday-ui/src/ManuscriptCard.js
index f06c5557a6e8a5d442d6b230df00cc92b76b9370..269c0401842819645308600decec57ae403e711b 100644
--- a/packages/component-faraday-ui/src/ManuscriptCard.js
+++ b/packages/component-faraday-ui/src/ManuscriptCard.js
@@ -52,18 +52,23 @@ const ManuscriptCard = ({
           </Row>
         )}
         <Row alignItems="center" justify="flex-start" mb={1}>
-          <Text customId mr={1}>{`ID ${customId}`}</Text>
+          {customId && <Text customId mr={1}>{`ID ${customId}`}</Text>}
           {submitted && (
             <DateParser humanizeThreshold={0} timestamp={submitted}>
-              {timestamp => <Text mr={3}>Submitted on {timestamp}</Text>}
+              {(timestamp, timeAgo) => (
+                <Text
+                  mr={3}
+                >{`Submitted on ${timestamp} (${timeAgo} ago)`}</Text>
+              )}
             </DateParser>
           )}
           <Text>{manuscriptType.label || type}</Text>
-          {journal && (
-            <Text journal ml={1}>
-              {journal}
-            </Text>
-          )}
+          {journal &&
+            (manuscriptType.label || type) && (
+              <Text journal ml={1}>
+                {journal}
+              </Text>
+            )}
         </Row>
         <Row alignItems="center" justify="flex-start" mb={1}>
           <H4>Handling editor</H4>
diff --git a/packages/component-user-manager/src/Users.js b/packages/component-user-manager/src/Users.js
index 581d7b87972085670892b8004f22cb54442a5861..9cc9c3f43fdda0bf00af9765aa5d28ca43bcb008 100644
--- a/packages/component-user-manager/src/Users.js
+++ b/packages/component-user-manager/src/Users.js
@@ -1,3 +1,5 @@
+const config = require('config')
+const jwt = require('jsonwebtoken')
 const bodyParser = require('body-parser')
 const orcidRoutes = require('./routes/users/linkOrcid')
 
@@ -167,6 +169,7 @@ const Users = app => {
    * @apiGroup Users
    * @apiSuccessExample {json} Success
    *    HTTP/1.1 200 OK
+   *    { users:
    *    [{
    *      "id": "a6184463-b17a-42f8-b02b-ae1d755cdc6b",
    *      "type": "user",
@@ -201,6 +204,7 @@ const Users = app => {
    *      "isSubmitting": false,
    *      "isCorresponding": false,
    *    }]
+   *    }
    * @apiErrorExample {json} List errors
    *    HTTP/1.1 403 Unauthorized
    */
@@ -209,9 +213,65 @@ const Users = app => {
     authBearer,
     require(`./routes/users/get`)(app.locals.models),
   )
+  /**
+   * @api {post} /api/users Create user
+   * @apiGroup Users
+   * @apiParamExample {json} Body
+   *    {
+   *      "password": "currentPassword",
+   *      "email": "email@example.com",
+   *      "firstName": "John",
+   *      "lastName": "Smith",
+   *      "affiliation": "UCLA",
+   *      "title": "Mr"
+   *    }
+   * @apiSuccessExample {json} Success
+   *    HTTP/1.1 200 OK
+   *    {
+   *      "id": "a6184463-b17a-42f8-b02b-ae1d755cdc6b",
+   *      "type": "user",
+   *      "admin": false,
+   *      "email": "email@example.com",
+   *      "teams": [],
+   *      "username": "email@example.com",
+   *      "fragments": [],
+   *      "collections": [],
+   *      "isConfirmed": true,
+   *      "editorInChief": false,
+   *      "handlingEditor": false,
+   *      "notifications": {
+   *        "email": {
+   *           "system": true,
+   *           "user": true
+   *         }
+   *       }
+   *    }
+   * @apiErrorExample {json} Reset password errors
+   *    HTTP/1.1 400 Bad Request
+   *    HTTP/1.1 404 Not Found
+   */
+  app.post(
+    '/api/users',
+    authorize,
+    require('./routes/users/post')(app.locals.models),
+  )
 
   // register ORCID authentication strategy
   orcidRoutes(app)
 }
 
+const authorize = async (req, res, next) => {
+  if (req.headers.authorization) {
+    const [, bToken] = req.headers.authorization.split(' ')
+    try {
+      const payload = jwt.verify(bToken, config.get('pubsweet-server.secret'))
+      req.user = payload.id
+      return next()
+    } catch (e) {
+      return res.status(403).json({ error: 'Unauthorized' })
+    }
+  }
+  return next()
+}
+
 module.exports = Users
diff --git a/packages/component-user-manager/src/routes/users/post.js b/packages/component-user-manager/src/routes/users/post.js
new file mode 100644
index 0000000000000000000000000000000000000000..32870956242c4642678383795848b6bb96946d80
--- /dev/null
+++ b/packages/component-user-manager/src/routes/users/post.js
@@ -0,0 +1,52 @@
+const { pick } = require('lodash')
+const Chance = require('chance')
+
+const chance = new Chance()
+
+module.exports = models => async (req, res) => {
+  if (req.user) {
+    const admin = await models.User.find(req.user)
+    if (!admin.admin) {
+      return res.status(403).json({ error: 'Unauthorized' })
+    }
+  } else {
+    if (!req.body.agreeTC) {
+      return res.status(403).json({
+        error: 'Terms & Conditions must be read and approved.',
+      })
+    }
+    req.body = pick(req.body, [
+      'email',
+      'title',
+      'country',
+      'firstName',
+      'lastName',
+      'password',
+      'affiliation',
+    ])
+    req.body = {
+      ...req.body,
+      admin: false,
+      isActive: true,
+      isConfirmed: false,
+      handlingEditor: false,
+      editorInChief: false,
+      username: req.body.email,
+      confirmationToken: chance.hash(),
+      notifications: {
+        email: {
+          system: true,
+          user: true,
+        },
+      },
+    }
+  }
+  let user = new models.User(req.body)
+
+  try {
+    user = await user.save()
+    return res.status(201).json(user)
+  } catch (err) {
+    return res.status(400).json({ error: err.message })
+  }
+}
diff --git a/packages/components-faraday/src/components/Dashboard/Dashboard.js b/packages/components-faraday/src/components/Dashboard/Dashboard.js
index 82137f785d294edbe2d8cf5996a492652b6b348b..0c106443fd6d2da18ebbdce662c5d738bc6b8dd8 100644
--- a/packages/components-faraday/src/components/Dashboard/Dashboard.js
+++ b/packages/components-faraday/src/components/Dashboard/Dashboard.js
@@ -23,6 +23,6 @@ const Dashboard = ({
 
 export default compose(
   withProps(({ dashboard, filterItems }) => ({
-    dashboardItems: filterItems(dashboard.all),
+    dashboardItems: filterItems(dashboard),
   })),
 )(Dashboard)
diff --git a/packages/components-faraday/src/components/Dashboard/DashboardPage.js b/packages/components-faraday/src/components/Dashboard/DashboardPage.js
index 944329379b27e97f83a5d770b1a50ea49142eaa7..6831dbc0265ec953396fafa62fe49e8bae853af9 100644
--- a/packages/components-faraday/src/components/Dashboard/DashboardPage.js
+++ b/packages/components-faraday/src/components/Dashboard/DashboardPage.js
@@ -5,9 +5,12 @@ import { withJournal } from 'xpub-journal'
 import { ConnectPage } from 'xpub-connect'
 import { withRouter } from 'react-router-dom'
 import { compose, withContext } from 'recompose'
-import { newestFirst, selectCurrentUser } from 'xpub-selectors'
+import { selectCurrentUser } from 'xpub-selectors'
 
-import { getUserPermissions } from 'pubsweet-component-faraday-selectors'
+import {
+  getUserPermissions,
+  newestFirstParseCustomId,
+} from 'pubsweet-component-faraday-selectors'
 
 import { Dashboard } from './'
 import { priorityFilter, orderFilter, withFiltersHOC } from '../Filters'
@@ -18,24 +21,8 @@ export default compose(
     state => {
       const { collections, conversion } = state
       const currentUser = selectCurrentUser(state)
-      const sortedCollections = newestFirst(collections)
+      const dashboard = newestFirstParseCustomId(collections)
 
-      const dashboard = {
-        owner: sortedCollections.filter(
-          collection =>
-            collection.owners &&
-            collection.owners.some(owner => owner.id === currentUser.id),
-        ),
-        reviewer: sortedCollections.filter(
-          collection =>
-            collection.reviewers &&
-            collection.reviewers.some(
-              reviewer => reviewer && reviewer.user === currentUser.id,
-            ),
-        ),
-
-        all: sortedCollections,
-      }
       const userPermissions = getUserPermissions(state)
       return {
         dashboard,
diff --git a/packages/components-faraday/src/components/SignUp/utils.js b/packages/components-faraday/src/components/SignUp/utils.js
index bf27a045194a52240357280db2cd268a42a4f497..3a9fd998810f022e1f270db62c10ab020a8bf29b 100644
--- a/packages/components-faraday/src/components/SignUp/utils.js
+++ b/packages/components-faraday/src/components/SignUp/utils.js
@@ -5,28 +5,8 @@ import { loginUser } from 'pubsweet-component-login/actions'
 
 import { handleFormError } from '../utils'
 
-const generatePasswordHash = () =>
-  Array.from({ length: 4 }, () =>
-    Math.random()
-      .toString(36)
-      .slice(4),
-  ).join('')
-
 export const parseSignupAuthor = ({ token, confirmPassword, ...values }) => ({
   ...values,
-  admin: false,
-  isActive: true,
-  isConfirmed: false,
-  editorInChief: false,
-  handlingEditor: false,
-  username: values.email,
-  confirmationToken: generatePasswordHash(),
-  notifications: {
-    email: {
-      system: true,
-      user: true,
-    },
-  },
 })
 
 export const parseSearchParams = url => {
diff --git a/packages/xpub-faraday/app/config/journal/metadata.js b/packages/xpub-faraday/app/config/journal/metadata.js
index a204afcbc11b0e9a967180450991778cfde39ddf..d23e29ac87bd7daba4425925e1969f69a0beeecc 100644
--- a/packages/xpub-faraday/app/config/journal/metadata.js
+++ b/packages/xpub-faraday/app/config/journal/metadata.js
@@ -2,7 +2,7 @@ module.exports = {
   issn: '2474-7394',
   logo: '/assets/logo-hindawi@2x.png',
   nameText: 'Bioinorganic Chemistry and Applications',
-  email: 'bca.support@hindawi.com',
+  email: process.env.EMAIL_SENDER || 'bca.support@hindawi.com',
   mts: {
     doctype: 'article SYSTEM "JATS-archivearticle1-mathml3.dtd"',
     dtdVersion: '1.1d1',
diff --git a/packages/xpub-faraday/webpack/webpack.production.config.js b/packages/xpub-faraday/webpack/webpack.production.config.js
index 0d39669864461e3188c03bf231076559a84d6ab4..c96a217e987c9dbd66eae7406e58b9eb8e0160a8 100644
--- a/packages/xpub-faraday/webpack/webpack.production.config.js
+++ b/packages/xpub-faraday/webpack/webpack.production.config.js
@@ -48,14 +48,10 @@ module.exports = [
                 }); var f = d.getElementsByTagName(s)[0],
                     j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src =
                         'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f);
-            })(window, document, 'script', 'dataLayer', '${
-              process.env.GA_KEY
-            }');</script>
+            })(window, document, 'script', 'dataLayer', 'GTM-5V2LT8L');</script>
         <!-- End Google Tag Manager -->`,
         gaBody: ` <!-- Google Tag Manager (noscript) -->
-        <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=${
-          process.env.GA_KEY
-        }" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
+        <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5V2LT8L" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
         <!-- End Google Tag Manager (noscript) -->`,
       }),
       new webpack.DefinePlugin({
diff --git a/scripts/wait-for-it.sh b/scripts/wait-for-it.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ea896a848ceabb0234802257d1fb78ba6eb1b4cb
--- /dev/null
+++ b/scripts/wait-for-it.sh
@@ -0,0 +1,178 @@
+#!/usr/bin/env bash
+#   Use this script to test if a given TCP host/port are available
+
+cmdname=$(basename $0)
+
+echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
+
+usage()
+{
+    cat << USAGE >&2
+Usage:
+    $cmdname host:port [-s] [-t timeout] [-- command args]
+    -h HOST | --host=HOST       Host or IP under test
+    -p PORT | --port=PORT       TCP port under test
+                                Alternatively, you specify the host and port as host:port
+    -s | --strict               Only execute subcommand if the test succeeds
+    -q | --quiet                Don't output any status messages
+    -t TIMEOUT | --timeout=TIMEOUT
+                                Timeout in seconds, zero for no timeout
+    -- COMMAND ARGS             Execute command with args after the test finishes
+USAGE
+    exit 1
+}
+
+wait_for()
+{
+    if [[ $TIMEOUT -gt 0 ]]; then
+        echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT"
+    else
+        echoerr "$cmdname: waiting for $HOST:$PORT without a timeout"
+    fi
+    start_ts=$(date +%s)
+    while :
+    do
+        if [[ $ISBUSY -eq 1 ]]; then
+            nc -z $HOST $PORT
+            result=$?
+        else
+            (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1
+            result=$?
+        fi
+        if [[ $result -eq 0 ]]; then
+            end_ts=$(date +%s)
+            echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds"
+            break
+        fi
+        sleep 1
+    done
+    return $result
+}
+
+wait_for_wrapper()
+{
+    # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
+    if [[ $QUIET -eq 1 ]]; then
+        timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
+    else
+        timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
+    fi
+    PID=$!
+    trap "kill -INT -$PID" INT
+    wait $PID
+    RESULT=$?
+    if [[ $RESULT -ne 0 ]]; then
+        echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT"
+    fi
+    return $RESULT
+}
+
+# process arguments
+while [[ $# -gt 0 ]]
+do
+    case "$1" in
+        *:* )
+        hostport=(${1//:/ })
+        HOST=${hostport[0]}
+        PORT=${hostport[1]}
+        shift 1
+        ;;
+        --child)
+        CHILD=1
+        shift 1
+        ;;
+        -q | --quiet)
+        QUIET=1
+        shift 1
+        ;;
+        -s | --strict)
+        STRICT=1
+        shift 1
+        ;;
+        -h)
+        HOST="$2"
+        if [[ $HOST == "" ]]; then break; fi
+        shift 2
+        ;;
+        --host=*)
+        HOST="${1#*=}"
+        shift 1
+        ;;
+        -p)
+        PORT="$2"
+        if [[ $PORT == "" ]]; then break; fi
+        shift 2
+        ;;
+        --port=*)
+        PORT="${1#*=}"
+        shift 1
+        ;;
+        -t)
+        TIMEOUT="$2"
+        if [[ $TIMEOUT == "" ]]; then break; fi
+        shift 2
+        ;;
+        --timeout=*)
+        TIMEOUT="${1#*=}"
+        shift 1
+        ;;
+        --)
+        shift
+        CLI=("$@")
+        break
+        ;;
+        --help)
+        usage
+        ;;
+        *)
+        echoerr "Unknown argument: $1"
+        usage
+        ;;
+    esac
+done
+
+if [[ "$HOST" == "" || "$PORT" == "" ]]; then
+    echoerr "Error: you need to provide a host and port to test."
+    usage
+fi
+
+TIMEOUT=${TIMEOUT:-15}
+STRICT=${STRICT:-0}
+CHILD=${CHILD:-0}
+QUIET=${QUIET:-0}
+
+# check to see if timeout is from busybox?
+# check to see if timeout is from busybox?
+TIMEOUT_PATH=$(realpath $(which timeout))
+if [[ $TIMEOUT_PATH =~ "busybox" ]]; then
+        ISBUSY=1
+        BUSYTIMEFLAG="-t"
+else
+        ISBUSY=0
+        BUSYTIMEFLAG=""
+fi
+
+if [[ $CHILD -gt 0 ]]; then
+    wait_for
+    RESULT=$?
+    exit $RESULT
+else
+    if [[ $TIMEOUT -gt 0 ]]; then
+        wait_for_wrapper
+        RESULT=$?
+    else
+        wait_for
+        RESULT=$?
+    fi
+fi
+
+if [[ $CLI != "" ]]; then
+    if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then
+        echoerr "$cmdname: strict mode, refusing to execute subprocess"
+        exit $RESULT
+    fi
+    exec "${CLI[@]}"
+else
+    exit $RESULT
+fi
+