diff --git a/server/model-manuscript/src/graphql.js b/server/model-manuscript/src/graphql.js
index c65b23affceefb6f9e7689b6a4efc0d080881074..81e51a136d45c495fe6b4071cf22e79ee98543bd 100644
--- a/server/model-manuscript/src/graphql.js
+++ b/server/model-manuscript/src/graphql.js
@@ -2,6 +2,42 @@
 const detailsForURLResolver = require('./detailsForURLResolver')
 const { ref, raw } = require('objection')
 
+const ManuscriptResolvers = ({ isVersion }) => {
+  const resolvers = {
+    submission(parent) {
+      return JSON.stringify(parent.submission)
+    },
+    async reviews(parent, _, ctx) {
+      return parent.reviews
+        ? parent.reviews
+        : (
+            await ctx.models.Manuscript.query().findById(parent.id)
+          ).$relatedQuery('reviews')
+    },
+    async teams(parent, _, ctx) {
+      return parent.teams
+        ? parent.teams
+        : (
+            await ctx.models.Manuscript.query().findById(parent.id)
+          ).$relatedQuery('teams')
+    },
+    meta(parent) {
+      return { ...parent.meta, manuscriptId: parent.id }
+    },
+  }
+  if (!isVersion) {
+    resolvers.manuscriptVersions = async (parent, _, ctx) => {
+      if (!parent.manuscriptVersions.length) {
+        return ctx.models.Manuscript.relatedQuery('manuscriptVersions')
+          .for(parent.id)
+          .orderBy('created', 'desc')
+      }
+      return parent.manuscriptVersions
+    }
+  }
+  return resolvers
+}
+
 const resolvers = {
   Mutation: {
     async createManuscript(_, vars, ctx) {
@@ -124,6 +160,7 @@ const resolvers = {
     async updateManuscript(_, { id, input }, ctx) {
       const data = JSON.parse(input)
       const manuscript = await ctx.models.Manuscript.query().findById(id)
+
       const update = Object.assign({}, manuscript, data)
       // We specifically merge submission, as it itself has nested properties
       // But we don't want to do a deep merge unconditionally, as that prevents
@@ -133,9 +170,35 @@ const resolvers = {
         manuscript.submission,
         data.submission,
       )
-      // const update.submission =
+      // if (manuscript.status === 'revise') {
+      //   return manuscript.createNewVersion(update)
+      // }
       return ctx.models.Manuscript.query().updateAndFetchById(id, update)
     },
+
+    async createNewVersion(_, { id }, ctx) {
+      const manuscript = await ctx.models.Manuscript.query().findById(id)
+      return manuscript.createNewVersion()
+    },
+    async submitManuscript(_, { id, input }, ctx) {
+      const data = JSON.parse(input)
+      const manuscript = await ctx.models.Manuscript.query().findById(id)
+      const update = Object.assign({}, manuscript, data)
+      // We specifically merge submission, as it itself has nested properties
+      // But we don't want to do a deep merge unconditionally, as that prevents
+      // any kind of deletion happening.
+      update.submission = Object.assign(
+        {},
+        manuscript.submission,
+        data.submission,
+      )
+
+      // if (manuscript.status === 'revise') {
+      //   return manuscript.createNewVersion(update)
+      // }
+      return ctx.models.Manuscript.query().updateAndFetchById(id, update)
+    },
+
     async makeDecision(_, { id, decision }, ctx) {
       const manuscript = await ctx.models.Manuscript.query().findById(id)
       manuscript.decision = decision
@@ -217,7 +280,9 @@ const resolvers = {
 
       const manuscript = await Manuscript.query()
         .findById(id)
-        .eager('[teams, channels, reviews.[user, comments], files]')
+        .withGraphFetched(
+          '[teams, channels, files, reviews.[user, comments], manuscriptVersions(orderByCreated)]',
+        )
 
       if (!manuscript.meta) {
         manuscript.meta = {}
@@ -241,7 +306,12 @@ const resolvers = {
       return manuscript
     },
     async manuscripts(_, { where }, ctx) {
-      return ctx.models.Manuscript.query().eager('[teams, reviews]')
+      return ctx.models.Manuscript.query()
+        .withGraphFetched(
+          '[teams, reviews, manuscriptVersions(orderByCreated)]',
+        )
+        .where({ parentId: null })
+        .orderBy('created', 'desc')
     },
     async publishedManuscripts(_, { offset, limit }, ctx) {
       const query = ctx.models.Manuscript.query()
@@ -262,7 +332,14 @@ const resolvers = {
       }
     },
     async paginatedManuscripts(_, { sort, offset, limit, filter }, ctx) {
-      const query = ctx.models.Manuscript.query().eager('submitter')
+      const query = ctx.models.Manuscript.query()
+        .where({ parentId: null })
+        .withGraphFetched('[submitter, manuscriptVersions(orderByCreated)]')
+        .modifiers({
+          orderByCreated(builder) {
+            builder.orderBy('created', 'desc')
+          },
+        })
 
       if (filter && filter.status) {
         query.where({ status: filter.status })
@@ -302,33 +379,8 @@ const resolvers = {
   // We want submission into to come out as a stringified JSON, so that we don't have to
   // change our queries if the submission form changes. We still want to store it as JSONB
   // so that we can easily search through the information within.
-  Manuscript: {
-    submission(parent) {
-      return JSON.stringify(parent.submission)
-    },
-    async reviews(parent, _, ctx) {
-      return parent.reviews
-        ? parent.reviews
-        : (
-            await ctx.models.Manuscript.query().findById(parent.id)
-          ).$relatedQuery('reviews')
-    },
-    async teams(parent, _, ctx) {
-      return parent.teams
-        ? parent.teams
-        : (
-            await ctx.models.Manuscript.query().findById(parent.id)
-          ).$relatedQuery('teams')
-    },
-    meta(parent) {
-      return { ...parent.meta, manuscriptId: parent.id }
-    },
-  },
-  ManuscriptVersion: {
-    submission(parent) {
-      return JSON.stringify(parent.submission)
-    },
-  },
+  Manuscript: ManuscriptResolvers({ isVersion: false }),
+  ManuscriptVersion: ManuscriptResolvers({ isVersion: true }),
 }
 
 const typeDefs = `
@@ -371,6 +423,7 @@ const typeDefs = `
   extend type Mutation {
     createManuscript(input: ManuscriptInput): Manuscript!
     updateManuscript(id: ID!, input: String): Manuscript!
+    submitManuscript(id: ID!, input: String): Manuscript!
     makeDecision(id: ID!, decision: String): Manuscript!
     deleteManuscript(id: ID!): ID!
     reviewerResponse(currentUserId: ID, action: String, teamId: ID! ): Team
@@ -378,6 +431,7 @@ const typeDefs = `
     addReviewer(manuscriptId: ID!, userId: ID!): Team
     removeReviewer(manuscriptId: ID!, userId: ID!): Team
     publishManuscript(id: ID!): Manuscript
+    createNewVersion(id: ID!): Manuscript
   }
 
   type Manuscript implements Object {
@@ -413,7 +467,9 @@ const typeDefs = `
     authors: [Author]
     meta: ManuscriptMeta
     submission: String
+    submitter: User
     published: DateTime
+    parentId: ID
   }
 
   input ManuscriptInput {
diff --git a/server/model-manuscript/src/manuscript.js b/server/model-manuscript/src/manuscript.js
index 38317a3928ebe287a5568a6c236722c87efc08af..cd93e8bdfd7f219934bde011a4efb1174da69685 100644
--- a/server/model-manuscript/src/manuscript.js
+++ b/server/model-manuscript/src/manuscript.js
@@ -13,48 +13,13 @@ class Manuscript extends BaseModel {
     this.type = 'Manuscript'
   }
 
-  // static async myManuscripts(myManuscripts) {
-  //   const mainManuscript = {}
-  //   myManuscripts.forEach(manuscript => {
-  //     if (!mainManuscript[manuscript.parentId || manuscript.id]) {
-  //       mainManuscript[manuscript.parentId || manuscript.id] = manuscript
-  //     } else {
-  //       const checkManuscript =
-  //         mainManuscript[manuscript.parentId || manuscript.id]
-  //       // Compare Dates
-  //       const dateCheckManuscript = new Date(checkManuscript.created).getTime()
-  //       const dateManuscript = new Date(manuscript.created).getTime()
-  //       if (dateManuscript >= dateCheckManuscript) {
-  //         mainManuscript[manuscript.parentId || manuscript.id] = manuscript
-  //       }
-  //     }
-  //   })
-
-  //   const latestManuscripts = values(mainManuscript)
-  //   await Promise.all(
-  //     latestManuscripts.map(async manuscript => {
-  //       manuscript.teams = await new Manuscript(manuscript).getTeams()
-  //       manuscript.reviews = await new Manuscript(manuscript).getReviews()
-  //       manuscript.manuscriptVersions =
-  //         (await manuscript.getManuscriptVersions()) || []
-  //       return manuscript
-  //     }),
-  //   )
-
-  //   return latestManuscripts
-  // }
-
-  // async getTeams() {
-  //   const { Team } = require('@pubsweet/models')
-  //   const myTeams = await Team.query()
-  //     .where({
-  //       objectId: this.id,
-  //       objectType: 'Manuscript',
-  //     })
-  //     .eager('members')
-
-  //   return myTeams
-  // }
+  static get modifiers() {
+    return {
+      orderByCreated(builder) {
+        builder.orderBy('created', 'desc')
+      },
+    }
+  }
 
   async getReviews() {
     // TODO: Use relationships
@@ -98,61 +63,35 @@ class Manuscript extends BaseModel {
   }
 
   async createNewVersion() {
-    const { Team, File } = require('@pubsweet/models')
-
-    const manuscriptReviews = (await this.$query().eager('reviews')).reviews
-    const manuscriptTeams = (
-      await this.$query().eager('[teams, teams.members]')
-    ).teams
-    const teams = manuscriptTeams.filter(
-      team =>
-        team.role === 'author' ||
-        team.role === 'seniorEditor' ||
-        team.role === 'handlingEditor',
-    )
-
-    const manuscriptFiles = await File.query().where({
-      manuscriptId: this.id,
+    // Copy authors to the new version
+    const teams = await this.$relatedQuery('teams')
+      .where({ role: 'author' })
+      .withGraphFetched('members')
+    teams.forEach(t => {
+      delete t.id
+      t.members.forEach(tm => delete tm.id)
     })
 
-    const manuscriptDecision = manuscriptReviews.find(
-      review => review.isDecision,
-    )
+    // Copy files as well
+    const files = await this.$relatedQuery('files')
+    files.forEach(f => delete f.id)
 
-    const dataManuscript = await new Manuscript(
-      omit(cloneDeep(this), ['id', 'created', 'updated', 'decision']),
-    )
+    const newVersion = cloneDeep(this)
+    newVersion.teams = teams
+    newVersion.files = files
 
-    dataManuscript.status =
-      manuscriptDecision.recommendation === 'revise'
-        ? 'revising'
-        : manuscriptDecision.recommendation
-
-    dataManuscript.parentId = this.parentId || this.id
-    const newManuscript = await dataManuscript.save()
-
-    if (teams.length > 0) {
-      // Copy Teams to the new Version
-      await Promise.all(
-        teams.map(async team => {
-          team.manuscriptId = newManuscript.id
-          team.members = team.members.map(member => omit(member, 'id'))
-          await new Team(omit(team, ['id'])).saveGraph()
-        }),
-      )
+    if (this.decision === 'revise') {
+      newVersion.status = 'revising'
     }
 
-    // Copy Files to the new Version
-    await Promise.all(
-      manuscriptFiles.map(async file => {
-        const newFile = omit(file, ['id'])
-        newFile.manuscriptId = newManuscript.id
-        await new File(newFile).save()
-        return newFile
-      }),
+    // All versions should be linked to one parent, original manuscript
+    newVersion.parentId = this.parentId || this.id
+
+    const manuscript = await Manuscript.query().insertGraphAndFetch(
+      omit(cloneDeep(newVersion), ['id', 'created', 'updated', 'decision']),
     )
 
-    return this
+    return manuscript
   }
 
   static get relationMappings() {
@@ -207,6 +146,14 @@ class Manuscript extends BaseModel {
           to: 'manuscripts.parentId',
         },
       },
+      manuscriptVersions: {
+        relation: BaseModel.HasManyRelation,
+        modelClass: Manuscript,
+        join: {
+          from: 'manuscripts.id',
+          to: 'manuscripts.parentId',
+        },
+      },
     }
   }
 
diff --git a/server/model-review/src/graphql.js b/server/model-review/src/graphql.js
index 8132e4874c53852c0c53c34a780a482c15c671d7..a486fef8f30b109e9d283b8ce4dcf81c71db6b80 100644
--- a/server/model-review/src/graphql.js
+++ b/server/model-review/src/graphql.js
@@ -51,6 +51,13 @@ const resolvers = {
       return member.save()
     },
   },
+  Review: {
+    async user(parent, _, ctx) {
+      return parent.user
+        ? parent.user
+        : ctx.models.User.query().findById(parent.userId)
+    },
+  },
   ReviewComment: {
     async files(parent, _, ctx) {
       return parent.files
diff --git a/server/model-team/src/team_member.js b/server/model-team/src/team_member.js
index eff8dd732633a4249c9913b8f2ac221dec14dded..3fe2fafd5f6d10711b508183108459a9ab319eb6 100644
--- a/server/model-team/src/team_member.js
+++ b/server/model-team/src/team_member.js
@@ -42,7 +42,7 @@ class TeamMember extends BaseModel {
         userId: { type: 'string', format: 'uuid' },
         teamId: { type: 'string', format: 'uuid' },
         aliasId: { type: ['string', 'null'], format: 'uuid' },
-        status: { type: 'string' },
+        status: { type: ['string', 'null'] },
       },
     }
   }
diff --git a/server/model-user/src/graphql.js b/server/model-user/src/graphql.js
index 241ca795f8d0622f0da7d0ff144ca53a494ea721..0b2f947a35ef3c09db7dd385a71f3cca3f6ae22e 100644
--- a/server/model-user/src/graphql.js
+++ b/server/model-user/src/graphql.js
@@ -3,8 +3,15 @@ const { AuthorizationError, ConflictError } = require('@pubsweet/errors')
 
 const resolvers = {
   Query: {
-    user(_, { id }, ctx) {
-      return ctx.models.User.query().findById(id)
+    user(_, { id, username }, ctx) {
+      if (id) {
+        return ctx.models.User.query().findById(id)
+      } else if (username) {
+        return ctx.models.User.query()
+          .where({ username })
+          .first()
+      }
+      return null
     },
     async users(_, vars, ctx) {
       return ctx.models.User.query()