diff --git a/apps/files_versions/appinfo/info.xml b/apps/files_versions/appinfo/info.xml
index d2f873edb0748f6119b893e60e8f76bcb441caba..6d1b3085f80f24bb2c0466b440ad0bbf36e9462f 100644
--- a/apps/files_versions/appinfo/info.xml
+++ b/apps/files_versions/appinfo/info.xml
@@ -41,4 +41,8 @@
 			<collection>OCA\Files_Versions\Sabre\RootCollection</collection>
 		</collections>
 	</sabre>
+
+	<versions>
+		<backend for="OCP\Files\Storage\IStorage">OCA\Files_Versions\Versions\LegacyVersionsBackend</backend>
+	</versions>
 </info>
diff --git a/apps/files_versions/composer/composer/autoload_classmap.php b/apps/files_versions/composer/composer/autoload_classmap.php
index 4bb112b4f11b964c1c58e6e170b3ce9f5ad59510..1283e533914a27ce9cd86520ae6eafe6db7605aa 100644
--- a/apps/files_versions/composer/composer/autoload_classmap.php
+++ b/apps/files_versions/composer/composer/autoload_classmap.php
@@ -23,4 +23,11 @@ return array(
     'OCA\\Files_Versions\\Sabre\\VersionHome' => $baseDir . '/../lib/Sabre/VersionHome.php',
     'OCA\\Files_Versions\\Sabre\\VersionRoot' => $baseDir . '/../lib/Sabre/VersionRoot.php',
     'OCA\\Files_Versions\\Storage' => $baseDir . '/../lib/Storage.php',
+    'OCA\\Files_Versions\\Versions\\BackendNotFoundException' => $baseDir . '/../lib/Versions/BackendNotFoundException.php',
+    'OCA\\Files_Versions\\Versions\\IVersion' => $baseDir . '/../lib/Versions/IVersion.php',
+    'OCA\\Files_Versions\\Versions\\IVersionBackend' => $baseDir . '/../lib/Versions/IVersionBackend.php',
+    'OCA\\Files_Versions\\Versions\\IVersionManager' => $baseDir . '/../lib/Versions/IVersionManager.php',
+    'OCA\\Files_Versions\\Versions\\LegacyVersionsBackend' => $baseDir . '/../lib/Versions/LegacyVersionsBackend.php',
+    'OCA\\Files_Versions\\Versions\\Version' => $baseDir . '/../lib/Versions/Version.php',
+    'OCA\\Files_Versions\\Versions\\VersionManager' => $baseDir . '/../lib/Versions/VersionManager.php',
 );
diff --git a/apps/files_versions/composer/composer/autoload_static.php b/apps/files_versions/composer/composer/autoload_static.php
index 29bc592b41c9ca15675284eb4a1032a57062c231..6a6b753c2e509832a0aeb8fde729f01a7299731e 100644
--- a/apps/files_versions/composer/composer/autoload_static.php
+++ b/apps/files_versions/composer/composer/autoload_static.php
@@ -38,6 +38,13 @@ class ComposerStaticInitFiles_Versions
         'OCA\\Files_Versions\\Sabre\\VersionHome' => __DIR__ . '/..' . '/../lib/Sabre/VersionHome.php',
         'OCA\\Files_Versions\\Sabre\\VersionRoot' => __DIR__ . '/..' . '/../lib/Sabre/VersionRoot.php',
         'OCA\\Files_Versions\\Storage' => __DIR__ . '/..' . '/../lib/Storage.php',
+        'OCA\\Files_Versions\\Versions\\BackendNotFoundException' => __DIR__ . '/..' . '/../lib/Versions/BackendNotFoundException.php',
+        'OCA\\Files_Versions\\Versions\\IVersion' => __DIR__ . '/..' . '/../lib/Versions/IVersion.php',
+        'OCA\\Files_Versions\\Versions\\IVersionBackend' => __DIR__ . '/..' . '/../lib/Versions/IVersionBackend.php',
+        'OCA\\Files_Versions\\Versions\\IVersionManager' => __DIR__ . '/..' . '/../lib/Versions/IVersionManager.php',
+        'OCA\\Files_Versions\\Versions\\LegacyVersionsBackend' => __DIR__ . '/..' . '/../lib/Versions/LegacyVersionsBackend.php',
+        'OCA\\Files_Versions\\Versions\\Version' => __DIR__ . '/..' . '/../lib/Versions/Version.php',
+        'OCA\\Files_Versions\\Versions\\VersionManager' => __DIR__ . '/..' . '/../lib/Versions/VersionManager.php',
     );
 
     public static function getInitializer(ClassLoader $loader)
diff --git a/apps/files_versions/lib/AppInfo/Application.php b/apps/files_versions/lib/AppInfo/Application.php
index 340b5ab5cbdb45129dfc0c419421b3fcfbeefe9e..935556221fa506b5b290deb96f1612f42f5a20d8 100644
--- a/apps/files_versions/lib/AppInfo/Application.php
+++ b/apps/files_versions/lib/AppInfo/Application.php
@@ -24,9 +24,10 @@
 namespace OCA\Files_Versions\AppInfo;
 
 use OCA\DAV\Connector\Sabre\Principal;
+use OCA\Files_Versions\Versions\IVersionManager;
+use OCA\Files_Versions\Versions\VersionManager;
 use OCP\AppFramework\App;
-use OCA\Files_Versions\Expiration;
-use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\AppFramework\IAppContainer;
 use OCA\Files_Versions\Capabilities;
 
 class Application extends App {
@@ -43,14 +44,45 @@ class Application extends App {
 		/*
 		 * Register $principalBackend for the DAV collection
 		 */
-		$container->registerService('principalBackend', function () {
+		$container->registerService('principalBackend', function (IAppContainer $c) {
+			$server = $c->getServer();
 			return new Principal(
-				\OC::$server->getUserManager(),
-				\OC::$server->getGroupManager(),
-				\OC::$server->getShareManager(),
-				\OC::$server->getUserSession(),
-				\OC::$server->getConfig()
+				$server->getUserManager(),
+				$server->getGroupManager(),
+				$server->getShareManager(),
+				$server->getUserSession(),
+				$server->getConfig()
 			);
 		});
+
+		$container->registerService(IVersionManager::class, function(IAppContainer $c) {
+			return new VersionManager();
+		});
+
+		$this->registerVersionBackends();
+	}
+
+	public function registerVersionBackends() {
+		$server = $this->getContainer()->getServer();
+		$logger = $server->getLogger();
+		$appManager = $server->getAppManager();
+		/** @var IVersionManager $versionManager */
+		$versionManager = $this->getContainer()->getServer()->query(IVersionManager::class);
+		foreach($appManager->getInstalledApps() as $app) {
+			$appInfo = $appManager->getAppInfo($app);
+			if (isset($appInfo['versions'])) {
+				$backends = $appInfo['versions'];
+				foreach($backends as $backend) {
+					$class = $backend['@value'];
+					$for = $backend['@attributes']['for'];
+					try {
+						$backendObject = $server->query($class);
+						$versionManager->registerBackend($for, $backendObject);
+					} catch (\Exception $e) {
+						$logger->logException($e);
+					}
+				}
+			}
+		}
 	}
 }
diff --git a/apps/files_versions/lib/Controller/PreviewController.php b/apps/files_versions/lib/Controller/PreviewController.php
index b8bf464fb3ff423ef85d5c3de2e6b79a1d399ddb..f41250a89710fcf48bcac38e683126abd4288228 100644
--- a/apps/files_versions/lib/Controller/PreviewController.php
+++ b/apps/files_versions/lib/Controller/PreviewController.php
@@ -21,45 +21,53 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
+
 namespace OCA\Files_Versions\Controller;
 
+use OCA\Files_Versions\Versions\IVersionManager;
 use OCP\AppFramework\Controller;
 use OCP\AppFramework\Http;
 use OCP\AppFramework\Http\DataResponse;
 use OCP\AppFramework\Http\FileDisplayResponse;
-use OCP\Files\File;
-use OCP\Files\Folder;
 use OCP\Files\IMimeTypeDetector;
 use OCP\Files\IRootFolder;
 use OCP\Files\NotFoundException;
 use OCP\IPreview;
 use OCP\IRequest;
+use OCP\IUserSession;
 
 class PreviewController extends Controller {
 
 	/** @var IRootFolder */
 	private $rootFolder;
 
-	/** @var string */
-	private $userId;
+	/** @var IUserSession */
+	private $userSession;
 
 	/** @var IMimeTypeDetector */
 	private $mimeTypeDetector;
 
+	/** @var IVersionManager */
+	private $versionManager;
+
 	/** @var IPreview */
 	private $previewManager;
 
-	public function __construct($appName,
-								IRequest $request,
-								IRootFolder $rootFolder,
-								$userId,
-								IMimeTypeDetector $mimeTypeDetector,
-								IPreview $previewManager) {
+	public function __construct(
+		$appName,
+		IRequest $request,
+		IRootFolder $rootFolder,
+		IUserSession $userSession,
+		IMimeTypeDetector $mimeTypeDetector,
+		IVersionManager $versionManager,
+		IPreview $previewManager
+	) {
 		parent::__construct($appName, $request);
 
 		$this->rootFolder = $rootFolder;
-		$this->userId = $userId;
+		$this->userSession = $userSession;
 		$this->mimeTypeDetector = $mimeTypeDetector;
+		$this->versionManager = $versionManager;
 		$this->previewManager = $previewManager;
 	}
 
@@ -79,20 +87,17 @@ class PreviewController extends Controller {
 		$y = 44,
 		$version = ''
 	) {
-		if($file === '' || $version === '' || $x === 0 || $y === 0) {
+		if ($file === '' || $version === '' || $x === 0 || $y === 0) {
 			return new DataResponse([], Http::STATUS_BAD_REQUEST);
 		}
 
 		try {
-			$userFolder = $this->rootFolder->getUserFolder($this->userId);
-			/** @var Folder $versionFolder */
-			$versionFolder = $userFolder->getParent()->get('files_versions');
-			$mimeType = $this->mimeTypeDetector->detectPath($file);
-			$file = $versionFolder->get($file.'.v'.$version);
-
-			/** @var File $file */
-			$f = $this->previewManager->getPreview($file, $x, $y, true, IPreview::MODE_FILL, $mimeType);
-			return new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
+			$user = $this->userSession->getUser();
+			$userFolder = $this->rootFolder->getUserFolder($user->getUID());
+			$file = $userFolder->get($file);
+			$versionFile = $this->versionManager->getVersionFile($user, $file, (int)$version);
+			$preview = $this->previewManager->getPreview($versionFile, $x, $y, true, IPreview::MODE_FILL, $versionFile->getMimetype());
+			return new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => $preview->getMimeType()]);
 		} catch (NotFoundException $e) {
 			return new DataResponse([], Http::STATUS_NOT_FOUND);
 		} catch (\InvalidArgumentException $e) {
diff --git a/apps/files_versions/lib/Sabre/RestoreFolder.php b/apps/files_versions/lib/Sabre/RestoreFolder.php
index c398d02692bf47a8cd199cf436ae6b51d3babacf..c8504646bad5dd6ce585426d23f0b3b2bd955b81 100644
--- a/apps/files_versions/lib/Sabre/RestoreFolder.php
+++ b/apps/files_versions/lib/Sabre/RestoreFolder.php
@@ -24,6 +24,7 @@ declare(strict_types=1);
 
 namespace OCA\Files_Versions\Sabre;
 
+use OCP\IUser;
 use Sabre\DAV\Exception\Forbidden;
 use Sabre\DAV\ICollection;
 use Sabre\DAV\IMoveTarget;
@@ -31,14 +32,6 @@ use Sabre\DAV\INode;
 
 
 class RestoreFolder implements ICollection, IMoveTarget {
-
-	/** @var string */
-	protected $userId;
-
-	public function __construct(string $userId) {
-		$this->userId = $userId;
-	}
-
 	public function createFile($name, $data = null) {
 		throw new Forbidden();
 	}
@@ -80,7 +73,8 @@ class RestoreFolder implements ICollection, IMoveTarget {
 			return false;
 		}
 
-		return $sourceNode->rollBack();
+		$sourceNode->rollBack();
+		return true;
 	}
 
 }
diff --git a/apps/files_versions/lib/Sabre/RootCollection.php b/apps/files_versions/lib/Sabre/RootCollection.php
index ca5979573b5490e11f4d4bd28a5453a737f210c7..504c3362505bdb59670e292235ad9d69dd2f8577 100644
--- a/apps/files_versions/lib/Sabre/RootCollection.php
+++ b/apps/files_versions/lib/Sabre/RootCollection.php
@@ -20,10 +20,13 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
+
 namespace OCA\Files_Versions\Sabre;
 
+use OCA\Files_Versions\Versions\IVersionManager;
 use OCP\Files\IRootFolder;
 use OCP\IConfig;
+use OCP\IUserManager;
 use Sabre\DAV\INode;
 use Sabre\DAVACL\AbstractPrincipalCollection;
 use Sabre\DAVACL\PrincipalBackend;
@@ -33,12 +36,24 @@ class RootCollection extends AbstractPrincipalCollection {
 	/** @var IRootFolder */
 	private $rootFolder;
 
-	public function __construct(PrincipalBackend\BackendInterface $principalBackend,
-								IRootFolder $rootFolder,
-								IConfig $config) {
+	/** @var IUserManager */
+	private $userManager;
+
+	/** @var IVersionManager */
+	private $versionManager;
+
+	public function __construct(
+		PrincipalBackend\BackendInterface $principalBackend,
+		IRootFolder $rootFolder,
+		IConfig $config,
+		IUserManager $userManager,
+		IVersionManager $versionManager
+	) {
 		parent::__construct($principalBackend, 'principals/users');
 
 		$this->rootFolder = $rootFolder;
+		$this->userManager = $userManager;
+		$this->versionManager = $versionManager;
 
 		$this->disableListing = !$config->getSystemValue('debug', false);
 	}
@@ -54,12 +69,12 @@ class RootCollection extends AbstractPrincipalCollection {
 	 * @return INode
 	 */
 	public function getChildForPrincipal(array $principalInfo) {
-		list(,$name) = \Sabre\Uri\split($principalInfo['uri']);
+		list(, $name) = \Sabre\Uri\split($principalInfo['uri']);
 		$user = \OC::$server->getUserSession()->getUser();
 		if (is_null($user) || $name !== $user->getUID()) {
 			throw new \Sabre\DAV\Exception\Forbidden();
 		}
-		return new VersionHome($principalInfo, $this->rootFolder);
+		return new VersionHome($principalInfo, $this->rootFolder, $this->userManager, $this->versionManager);
 	}
 
 	public function getName() {
diff --git a/apps/files_versions/lib/Sabre/VersionCollection.php b/apps/files_versions/lib/Sabre/VersionCollection.php
index 481a5f491c3dadbf04a09b2e6f09f604e547f1dc..9a3a6a365f0115f8da628449cbcbc8bd102d9fe4 100644
--- a/apps/files_versions/lib/Sabre/VersionCollection.php
+++ b/apps/files_versions/lib/Sabre/VersionCollection.php
@@ -21,11 +21,15 @@ declare(strict_types=1);
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
+
 namespace OCA\Files_Versions\Sabre;
 
 use OCA\Files_Versions\Storage;
+use OCA\Files_Versions\Versions\IVersion;
+use OCA\Files_Versions\Versions\IVersionManager;
 use OCP\Files\File;
 use OCP\Files\Folder;
+use OCP\IUser;
 use Sabre\DAV\Exception\Forbidden;
 use Sabre\DAV\Exception\NotFound;
 use Sabre\DAV\ICollection;
@@ -37,13 +41,17 @@ class VersionCollection implements ICollection {
 	/** @var File */
 	private $file;
 
-	/** @var string */
-	private $userId;
+	/** @var IUser */
+	private $user;
+
+	/** @var IVersionManager */
+	private $versionManager;
 
-	public function __construct(Folder $userFolder, File $file, string $userId) {
+	public function __construct(Folder $userFolder, File $file, IUser $user, IVersionManager $versionManager) {
 		$this->userFolder = $userFolder;
 		$this->file = $file;
-		$this->userId = $userId;
+		$this->user = $user;
+		$this->versionManager = $versionManager;
 	}
 
 	public function createFile($name, $data = null) {
@@ -68,10 +76,10 @@ class VersionCollection implements ICollection {
 	}
 
 	public function getChildren(): array {
-		$versions = Storage::getVersions($this->userId, $this->userFolder->getRelativePath($this->file->getPath()));
+		$versions = $this->versionManager->getVersionsForFile($this->user, $this->file);
 
-		return array_map(function (array $data) {
-			return new VersionFile($data, $this->userFolder->getParent());
+		return array_map(function (IVersion $version) {
+			return new VersionFile($version, $this->versionManager);
 		}, $versions);
 	}
 
diff --git a/apps/files_versions/lib/Sabre/VersionFile.php b/apps/files_versions/lib/Sabre/VersionFile.php
index 347058448fce823c177b5124e89eb2cef6960c6d..2d630008d2a2471c4239d442fc2c40bc7debf5ca 100644
--- a/apps/files_versions/lib/Sabre/VersionFile.php
+++ b/apps/files_versions/lib/Sabre/VersionFile.php
@@ -21,26 +21,26 @@ declare(strict_types=1);
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
+
 namespace OCA\Files_Versions\Sabre;
 
-use OCA\Files_Versions\Storage;
-use OCP\Files\File;
-use OCP\Files\Folder;
+use OCA\Files_Versions\Versions\IVersion;
+use OCA\Files_Versions\Versions\IVersionManager;
 use OCP\Files\NotFoundException;
 use Sabre\DAV\Exception\Forbidden;
 use Sabre\DAV\Exception\NotFound;
 use Sabre\DAV\IFile;
 
 class VersionFile implements IFile {
-	/** @var array */
-	private $data;
+	/** @var IVersion */
+	private $version;
 
-	/** @var Folder */
-	private $userRoot;
+	/** @var IVersionManager */
+	private $versionManager;
 
-	public function __construct(array $data, Folder $userRoot) {
-		$this->data = $data;
-		$this->userRoot = $userRoot;
+	public function __construct(IVersion $version, IVersionManager $versionManager) {
+		$this->version = $version;
+		$this->versionManager = $versionManager;
 	}
 
 	public function put($data) {
@@ -49,27 +49,22 @@ class VersionFile implements IFile {
 
 	public function get() {
 		try {
-			/** @var Folder $versions */
-			$versions = $this->userRoot->get('files_versions');
-			/** @var File $version */
-			$version = $versions->get($this->data['path'].'.v'.$this->data['version']);
+			return $this->versionManager->read($this->version);
 		} catch (NotFoundException $e) {
 			throw new NotFound();
 		}
-
-		return $version->fopen('rb');
 	}
 
 	public function getContentType(): string {
-		return $this->data['mimetype'];
+		return $this->version->getMimeType();
 	}
 
 	public function getETag(): string {
-		return $this->data['version'];
+		return (string)$this->version->getRevisionId();
 	}
 
 	public function getSize(): int {
-		return $this->data['size'];
+		return $this->version->getSize();
 	}
 
 	public function delete() {
@@ -77,7 +72,7 @@ class VersionFile implements IFile {
 	}
 
 	public function getName(): string {
-		return $this->data['version'];
+		return (string)$this->version->getRevisionId();
 	}
 
 	public function setName($name) {
@@ -85,10 +80,10 @@ class VersionFile implements IFile {
 	}
 
 	public function getLastModified(): int {
-		return (int)$this->data['version'];
+		return $this->version->getTimestamp();
 	}
 
-	public function rollBack(): bool {
-		return Storage::rollback($this->data['path'], $this->data['version']);
+	public function rollBack() {
+		$this->versionManager->rollback($this->version);
 	}
 }
diff --git a/apps/files_versions/lib/Sabre/VersionHome.php b/apps/files_versions/lib/Sabre/VersionHome.php
index 7a99d2376d4acd4dfc3ddf30d76ae20a41fec87a..7be5974bbbea4160d2d38471a33d9759df17c259 100644
--- a/apps/files_versions/lib/Sabre/VersionHome.php
+++ b/apps/files_versions/lib/Sabre/VersionHome.php
@@ -20,9 +20,13 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
+
 namespace OCA\Files_Versions\Sabre;
 
+use OC\User\NoUserException;
+use OCA\Files_Versions\Versions\IVersionManager;
 use OCP\Files\IRootFolder;
+use OCP\IUserManager;
 use Sabre\DAV\Exception\Forbidden;
 use Sabre\DAV\ICollection;
 
@@ -34,9 +38,25 @@ class VersionHome implements ICollection {
 	/** @var IRootFolder */
 	private $rootFolder;
 
-	public function __construct(array $principalInfo, IRootFolder $rootFolder) {
+	/** @var IUserManager */
+	private $userManager;
+
+	/** @var IVersionManager */
+	private $versionManager;
+
+	public function __construct(array $principalInfo, IRootFolder $rootFolder, IUserManager $userManager, IVersionManager $versionManager) {
 		$this->principalInfo = $principalInfo;
 		$this->rootFolder = $rootFolder;
+		$this->userManager = $userManager;
+		$this->versionManager = $versionManager;
+	}
+
+	private function getUser() {
+		list(, $name) = \Sabre\Uri\split($this->principalInfo['uri']);
+		$user = $this->userManager->get($name);
+		if (!$user) {
+			throw new NoUserException();
+		}
 	}
 
 	public function delete() {
@@ -44,8 +64,7 @@ class VersionHome implements ICollection {
 	}
 
 	public function getName(): string {
-		list(,$name) = \Sabre\Uri\split($this->principalInfo['uri']);
-		return $name;
+		return $this->getUser()->getUID();
 	}
 
 	public function setName($name) {
@@ -61,22 +80,22 @@ class VersionHome implements ICollection {
 	}
 
 	public function getChild($name) {
-		list(,$userId) = \Sabre\Uri\split($this->principalInfo['uri']);
+		$user = $this->getUser();
 
 		if ($name === 'versions') {
-			return new VersionRoot($userId, $this->rootFolder);
+			return new VersionRoot($user, $this->rootFolder, $this->versionManager);
 		}
 		if ($name === 'restore') {
-			return new RestoreFolder($userId);
+			return new RestoreFolder();
 		}
 	}
 
 	public function getChildren() {
-		list(,$userId) = \Sabre\Uri\split($this->principalInfo['uri']);
+		$user = $this->getUser();
 
 		return [
-			new VersionRoot($userId, $this->rootFolder),
-			new RestoreFolder($userId),
+			new VersionRoot($user, $this->rootFolder, $this->versionManager),
+			new RestoreFolder(),
 		];
 	}
 
diff --git a/apps/files_versions/lib/Sabre/VersionRoot.php b/apps/files_versions/lib/Sabre/VersionRoot.php
index 743b1c6ef1b5004ebf9cfa13d972495d583da8a2..1c689a4d87bcabe00e7531a4903949e09b939538 100644
--- a/apps/files_versions/lib/Sabre/VersionRoot.php
+++ b/apps/files_versions/lib/Sabre/VersionRoot.php
@@ -23,23 +23,29 @@ declare(strict_types=1);
  */
 namespace OCA\Files_Versions\Sabre;
 
+use OCA\Files_Versions\Versions\IVersionManager;
 use OCP\Files\File;
 use OCP\Files\IRootFolder;
+use OCP\IUser;
 use Sabre\DAV\Exception\Forbidden;
 use Sabre\DAV\Exception\NotFound;
 use Sabre\DAV\ICollection;
 
 class VersionRoot implements ICollection {
 
-	/** @var string */
-	private $userId;
+	/** @var IUser */
+	private $user;
 
 	/** @var IRootFolder */
 	private $rootFolder;
 
-	public function __construct(string $userId, IRootFolder $rootFolder) {
-		$this->userId = $userId;
+	/** @var IVersionManager */
+	private $versionManager;
+
+	public function __construct(IUser $user, IRootFolder $rootFolder, IVersionManager $versionManager) {
+		$this->user = $user;
 		$this->rootFolder = $rootFolder;
+		$this->versionManager = $versionManager;
 	}
 
 	public function delete() {
@@ -63,7 +69,7 @@ class VersionRoot implements ICollection {
 	}
 
 	public function getChild($name) {
-		$userFolder = $this->rootFolder->getUserFolder($this->userId);
+		$userFolder = $this->rootFolder->getUserFolder($this->user->getUID());
 
 		$fileId = (int)$name;
 		$nodes = $userFolder->getById($fileId);
@@ -78,7 +84,7 @@ class VersionRoot implements ICollection {
 			throw new NotFound();
 		}
 
-		return new VersionCollection($userFolder, $node, $this->userId);
+		return new VersionCollection($userFolder, $node, $this->user, $this->versionManager);
 	}
 
 	public function getChildren(): array {
diff --git a/apps/files_versions/lib/Storage.php b/apps/files_versions/lib/Storage.php
index 401544cc5d74601a86c4e12ba5ec451226a64fc0..e2e4888cbcef5e95e677a6412c285a352fe7d9b8 100644
--- a/apps/files_versions/lib/Storage.php
+++ b/apps/files_versions/lib/Storage.php
@@ -48,6 +48,7 @@ use OC\Files\View;
 use OCA\Files_Versions\AppInfo\Application;
 use OCA\Files_Versions\Command\Expire;
 use OCA\Files_Versions\Events\CreateVersionEvent;
+use OCA\Files_Versions\Versions\IVersionManager;
 use OCP\Files\NotFoundException;
 use OCP\Lock\ILockingProvider;
 use OCP\User;
@@ -178,10 +179,10 @@ class Storage {
 		list($uid, $filename) = self::getUidAndFilename($filename);
 
 		$files_view = new View('/'.$uid .'/files');
-		$users_view = new View('/'.$uid);
 
 		$eventDispatcher = \OC::$server->getEventDispatcher();
-		$id = $files_view->getFileInfo($filename)->getId();
+		$fileInfo = $files_view->getFileInfo($filename);
+		$id = $fileInfo->getId();
 		$nodes = \OC::$server->getRootFolder()->getById($id);
 		foreach ($nodes as $node) {
 			$event = new CreateVersionEvent($node);
@@ -192,20 +193,16 @@ class Storage {
 		}
 
 		// no use making versions for empty files
-		if ($files_view->filesize($filename) === 0) {
+		if ($fileInfo->getSize() === 0) {
 			return false;
 		}
 
-		// create all parent folders
-		self::createMissingDirectories($filename, $users_view);
-
-		self::scheduleExpire($uid, $filename);
+		/** @var IVersionManager $versionManager */
+		$versionManager = \OC::$server->query(IVersionManager::class);
+		$userManager = \OC::$server->getUserManager();
+		$user = $userManager->get($uid);
 
-		// store a new version of a file
-		$mtime = $users_view->filemtime('files/' . $filename);
-		$users_view->copy('files/' . $filename, 'files_versions/' . $filename . '.v' . $mtime);
-		// call getFileInfo to enforce a file cache entry for the new version
-		$users_view->getFileInfo('files_versions/' . $filename . '.v' . $mtime);
+		$versionManager->createVersion($user, $fileInfo);
 	}
 
 
@@ -695,7 +692,7 @@ class Storage {
 	 * @param string $uid owner of the file
 	 * @param string $fileName file/folder for which to schedule expiration
 	 */
-	private static function scheduleExpire($uid, $fileName) {
+	public static function scheduleExpire($uid, $fileName) {
 		// let the admin disable auto expire
 		$expiration = self::getExpiration();
 		if ($expiration->isEnabled()) {
@@ -833,7 +830,7 @@ class Storage {
 	 * "files" folder
 	 * @param View $view view on data/user/
 	 */
-	private static function createMissingDirectories($filename, $view) {
+	public static function createMissingDirectories($filename, $view) {
 		$dirname = Filesystem::normalizePath(dirname($filename));
 		$dirParts = explode('/', $dirname);
 		$dir = "/files_versions";
diff --git a/apps/files_versions/lib/Versions/BackendNotFoundException.php b/apps/files_versions/lib/Versions/BackendNotFoundException.php
new file mode 100644
index 0000000000000000000000000000000000000000..09985a716b9a7bc4ceba8a26e6cccc5821143275
--- /dev/null
+++ b/apps/files_versions/lib/Versions/BackendNotFoundException.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_Versions\Versions;
+
+class BackendNotFoundException extends \Exception {
+
+}
diff --git a/apps/files_versions/lib/Versions/IVersion.php b/apps/files_versions/lib/Versions/IVersion.php
new file mode 100644
index 0000000000000000000000000000000000000000..b6fc95814d84b9c32ba20066d909b5e82592dd0b
--- /dev/null
+++ b/apps/files_versions/lib/Versions/IVersion.php
@@ -0,0 +1,99 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_Versions\Versions;
+
+use OCP\Files\FileInfo;
+use OCP\IUser;
+
+/**
+ * @since 15.0.0
+ */
+interface IVersion {
+	/**
+	 * @return IVersionBackend
+	 * @since 15.0.0
+	 */
+	public function getBackend(): IVersionBackend;
+
+	/**
+	 * Get the file info of the source file
+	 *
+	 * @return FileInfo
+	 * @since 15.0.0
+	 */
+	public function getSourceFile(): FileInfo;
+
+	/**
+	 * Get the id of the revision for the file
+	 *
+	 * @return int
+	 * @since 15.0.0
+	 */
+	public function getRevisionId(): int;
+
+	/**
+	 * Get the timestamp this version was created
+	 *
+	 * @return int
+	 * @since 15.0.0
+	 */
+	public function getTimestamp(): int;
+
+	/**
+	 * Get the size of this version
+	 *
+	 * @return int
+	 * @since 15.0.0
+	 */
+	public function getSize(): int;
+
+	/**
+	 * Get the name of the source file at the time of making this version
+	 *
+	 * @return string
+	 * @since 15.0.0
+	 */
+	public function getSourceFileName(): string;
+
+	/**
+	 * Get the mimetype of this version
+	 *
+	 * @return string
+	 * @since 15.0.0
+	 */
+	public function getMimeType(): string;
+
+	/**
+	 * Get the path of this version
+	 *
+	 * @return string
+	 * @since 15.0.0
+	 */
+	public function getVersionPath(): string;
+
+	/**
+	 * @return IUser
+	 * @since 15.0.0
+	 */
+	public function getUser(): IUser;
+}
diff --git a/apps/files_versions/lib/Versions/IVersionBackend.php b/apps/files_versions/lib/Versions/IVersionBackend.php
new file mode 100644
index 0000000000000000000000000000000000000000..616d535f7fd5b787c2c57f4fea96a8099a5904db
--- /dev/null
+++ b/apps/files_versions/lib/Versions/IVersionBackend.php
@@ -0,0 +1,81 @@
+<?php declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_Versions\Versions;
+
+use OCP\Files\File;
+use OCP\Files\FileInfo;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\IUser;
+
+/**
+ * @since 15.0.0
+ */
+interface IVersionBackend {
+	/**
+	 * Get all versions for a file
+	 *
+	 * @param IUser $user
+	 * @param FileInfo $file
+	 * @return IVersion[]
+	 * @since 15.0.0
+	 */
+	public function getVersionsForFile(IUser $user, FileInfo $file): array;
+
+	/**
+	 * Create a new version for a file
+	 *
+	 * @param IUser $user
+	 * @param FileInfo $file
+	 * @since 15.0.0
+	 */
+	public function createVersion(IUser $user, FileInfo $file);
+
+	/**
+	 * Restore this version
+	 *
+	 * @param IVersion $version
+	 * @since 15.0.0
+	 */
+	public function rollback(IVersion $version);
+
+	/**
+	 * Open the file for reading
+	 *
+	 * @param IVersion $version
+	 * @return resource
+	 * @throws NotFoundException
+	 * @since 15.0.0
+	 */
+	public function read(IVersion $version);
+
+	/**
+	 * Get the preview for a specific version of a file
+	 *
+	 * @param IUser $user
+	 * @param FileInfo $sourceFile
+	 * @param int $revision
+	 * @return ISimpleFile
+	 * @since 15.0.0
+	 */
+	public function getVersionFile(IUser $user, FileInfo $sourceFile, int $revision): File;
+}
diff --git a/apps/files_versions/lib/Versions/IVersionManager.php b/apps/files_versions/lib/Versions/IVersionManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..748b649b1a2480e04cc1bf12b2225fffabea8b46
--- /dev/null
+++ b/apps/files_versions/lib/Versions/IVersionManager.php
@@ -0,0 +1,36 @@
+<?php declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_Versions\Versions;
+
+/**
+ * @since 15.0.0
+ */
+interface IVersionManager extends IVersionBackend {
+	/**
+	 * Register a new backend
+	 *
+	 * @param string $storageType
+	 * @param IVersionBackend $backend
+	 * @since 15.0.0
+	 */
+	public function registerBackend(string $storageType, IVersionBackend $backend);
+}
diff --git a/apps/files_versions/lib/Versions/LegacyVersionsBackend.php b/apps/files_versions/lib/Versions/LegacyVersionsBackend.php
new file mode 100644
index 0000000000000000000000000000000000000000..7293aca641e3a5d4c540fa2d98a34f689e00fcc3
--- /dev/null
+++ b/apps/files_versions/lib/Versions/LegacyVersionsBackend.php
@@ -0,0 +1,105 @@
+<?php declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_Versions\Versions;
+
+use OC\Files\View;
+use OCA\Files_Versions\Storage;
+use OCP\Files\File;
+use OCP\Files\FileInfo;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\IUser;
+
+class LegacyVersionsBackend implements IVersionBackend {
+	/** @var IRootFolder */
+	private $rootFolder;
+
+	public function __construct(IRootFolder $rootFolder) {
+		$this->rootFolder = $rootFolder;
+	}
+
+	public function getVersionsForFile(IUser $user, FileInfo $file): array {
+		$userFolder = $this->rootFolder->getUserFolder($user->getUID());
+		$versions = Storage::getVersions($user->getUID(), $userFolder->getRelativePath($file->getPath()));
+
+		return array_map(function (array $data) use ($file, $user) {
+			return new Version(
+				(int)$data['version'],
+				(int)$data['version'],
+				$data['name'],
+				(int)$data['size'],
+				$data['mimetype'],
+				$data['path'],
+				$file,
+				$this,
+				$user
+			);
+		}, $versions);
+	}
+
+	public function createVersion(IUser $user, FileInfo $file) {
+		$userFolder = $this->rootFolder->getUserFolder($user->getUID());
+		$relativePath = $userFolder->getRelativePath($file->getPath());
+		$userView = new View('/' . $user->getUID());
+		// create all parent folders
+		Storage::createMissingDirectories($relativePath, $userView);
+
+		Storage::scheduleExpire($user->getUID(), $relativePath);
+
+		// store a new version of a file
+		$userView->copy('files/' . $relativePath, 'files_versions/' . $relativePath . '.v' . $file->getMtime());
+		// ensure the file is scanned
+		$userView->getFileInfo('files_versions/' . $relativePath . '.v' . $file->getMtime());
+	}
+
+	public function rollback(IVersion $version) {
+		return Storage::rollback($version->getVersionPath(), $version->getRevisionId());
+	}
+
+	private function getVersionFolder(IUser $user): Folder {
+		$userRoot = $this->rootFolder->getUserFolder($user->getUID())
+			->getParent();
+		try {
+			/** @var Folder $folder */
+			$folder = $userRoot->get('files_versions');
+			return $folder;
+		} catch (NotFoundException $e) {
+			return $userRoot->newFolder('files_versions');
+		}
+	}
+
+	public function read(IVersion $version) {
+		$versions = $this->getVersionFolder($version->getUser());
+		/** @var File $file */
+		$file = $versions->get($version->getVersionPath() . '.v' . $version->getRevisionId());
+		return $file->fopen('r');
+	}
+
+	public function getVersionFile(IUser $user, FileInfo $sourceFile, int $revision): File {
+		$userFolder = $this->rootFolder->getUserFolder($user->getUID());
+		$versionFolder = $this->getVersionFolder($user);
+		/** @var File $file */
+		$file = $versionFolder->get($userFolder->getRelativePath($sourceFile->getPath()) . '.v' . $revision);
+		return $file;
+	}
+}
diff --git a/apps/files_versions/lib/Versions/Version.php b/apps/files_versions/lib/Versions/Version.php
new file mode 100644
index 0000000000000000000000000000000000000000..5988234db6140495e2b71ca17864fc291c37217c
--- /dev/null
+++ b/apps/files_versions/lib/Versions/Version.php
@@ -0,0 +1,113 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_Versions\Versions;
+
+use OCP\Files\FileInfo;
+use OCP\IUser;
+
+class Version implements IVersion {
+	/** @var int */
+	private $timestamp;
+
+	/** @var int */
+	private $revisionId;
+
+	/** @var string */
+	private $name;
+
+	/** @var int */
+	private $size;
+
+	/** @var string */
+	private $mimetype;
+
+	/** @var string */
+	private $path;
+
+	/** @var FileInfo */
+	private $sourceFileInfo;
+
+	/** @var IVersionBackend */
+	private $backend;
+
+	/** @var IUser */
+	private $user;
+
+	public function __construct(
+		int $timestamp,
+		int $revisionId,
+		string $name,
+		int $size,
+		string $mimetype,
+		string $path,
+		FileInfo $sourceFileInfo,
+		IVersionBackend $backend,
+		IUser $user
+	) {
+		$this->timestamp = $timestamp;
+		$this->revisionId = $revisionId;
+		$this->name = $name;
+		$this->size = $size;
+		$this->mimetype = $mimetype;
+		$this->path = $path;
+		$this->sourceFileInfo = $sourceFileInfo;
+		$this->backend = $backend;
+		$this->user = $user;
+	}
+
+	public function getBackend(): IVersionBackend {
+		return $this->backend;
+	}
+
+	public function getSourceFile(): FileInfo {
+		return $this->sourceFileInfo;
+	}
+
+	public function getRevisionId(): int {
+		return $this->revisionId;
+	}
+
+	public function getTimestamp(): int {
+		return $this->timestamp;
+	}
+
+	public function getSize(): int {
+		return $this->size;
+	}
+
+	public function getSourceFileName(): string {
+		return $this->name;
+	}
+
+	public function getMimeType(): string {
+		return $this->mimetype;
+	}
+
+	public function getVersionPath(): string {
+		return $this->path;
+	}
+
+	public function getUser(): IUser {
+		return $this->user;
+	}
+}
diff --git a/apps/files_versions/lib/Versions/VersionManager.php b/apps/files_versions/lib/Versions/VersionManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..757b6002710266731bcb6a6ca1efee1e6e792da2
--- /dev/null
+++ b/apps/files_versions/lib/Versions/VersionManager.php
@@ -0,0 +1,93 @@
+<?php declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_Versions\Versions;
+
+use OCP\Files\File;
+use OCP\Files\FileInfo;
+use OCP\Files\Storage\IStorage;
+use OCP\IUser;
+
+class VersionManager implements IVersionManager {
+	/** @var IVersionBackend[] */
+	private $backends = [];
+
+	public function registerBackend(string $storageType, IVersionBackend $backend) {
+		$this->backends[$storageType] = $backend;
+	}
+
+	/**
+	 * @return IVersionBackend[]
+	 */
+	private function getBackends(): array {
+		return $this->backends;
+	}
+
+	/**
+	 * @param IStorage $storage
+	 * @return IVersionBackend
+	 * @throws BackendNotFoundException
+	 */
+	public function getBackendForStorage(IStorage $storage): IVersionBackend {
+		$fullType = get_class($storage);
+		$backends = $this->getBackends();
+		$foundType = array_reduce(array_keys($backends), function ($type, $registeredType) use ($storage) {
+			if (
+				$storage->instanceOfStorage($registeredType) &&
+				($type === '' || is_subclass_of($registeredType, $type))
+			) {
+				return $registeredType;
+			} else {
+				return $type;
+			}
+		}, '');
+		if ($foundType === '') {
+			throw new BackendNotFoundException("Version backend for $fullType not found");
+		} else {
+			return $backends[$foundType];
+		}
+	}
+
+	public function getVersionsForFile(IUser $user, FileInfo $file): array {
+		$backend = $this->getBackendForStorage($file->getStorage());
+		return $backend->getVersionsForFile($user, $file);
+	}
+
+	public function createVersion(IUser $user, FileInfo $file) {
+		$backend = $this->getBackendForStorage($file->getStorage());
+		$backend->createVersion($user, $file);
+	}
+
+	public function rollback(IVersion $version) {
+		$backend = $version->getBackend();
+		return $backend->rollback($version);
+	}
+
+	public function read(IVersion $version) {
+		$backend = $version->getBackend();
+		return $backend->read($version);
+	}
+
+	public function getVersionFile(IUser $user, FileInfo $sourceFile, int $revision): File {
+		$backend = $this->getBackendForStorage($sourceFile->getStorage());
+		return $backend->getVersionFile($user, $sourceFile, $revision);
+	}
+}
diff --git a/apps/files_versions/tests/Controller/PreviewControllerTest.php b/apps/files_versions/tests/Controller/PreviewControllerTest.php
index 384f43cf495790a782a819007e07d0410de27f9c..7c248b363497d3d4218688b7a6ff647443ffffd4 100644
--- a/apps/files_versions/tests/Controller/PreviewControllerTest.php
+++ b/apps/files_versions/tests/Controller/PreviewControllerTest.php
@@ -20,9 +20,12 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
+
 namespace OCA\Files_Versions\Tests\Controller;
 
+use OC\User\User;
 use OCA\Files_Versions\Controller\PreviewController;
+use OCA\Files_Versions\Versions\IVersionManager;
 use OCP\AppFramework\Http;
 use OCP\AppFramework\Http\DataResponse;
 use OCP\AppFramework\Http\FileDisplayResponse;
@@ -34,6 +37,8 @@ use OCP\Files\NotFoundException;
 use OCP\Files\SimpleFS\ISimpleFile;
 use OCP\IPreview;
 use OCP\IRequest;
+use OCP\IUser;
+use OCP\IUserSession;
 use Test\TestCase;
 
 class PreviewControllerTest extends TestCase {
@@ -50,23 +55,39 @@ class PreviewControllerTest extends TestCase {
 	/** @var IPreview|\PHPUnit_Framework_MockObject_MockObject */
 	private $previewManager;
 
-	/** @var PreviewController */
+	/** @var PreviewController|\PHPUnit_Framework_MockObject_MockObject */
 	private $controller;
 
+	/** @var IUserSession|\PHPUnit_Framework_MockObject_MockObject */
+	private $userSession;
+
+	/** @var IVersionManager|\PHPUnit_Framework_MockObject_MockObject */
+	private $versionManager;
+
 	public function setUp() {
 		parent::setUp();
 
 		$this->rootFolder = $this->createMock(IRootFolder::class);
 		$this->userId = 'user';
+		$user = $this->createMock(IUser::class);
+		$user->expects($this->any())
+			->method('getUID')
+			->willReturn($this->userId);
 		$this->mimeTypeDetector = $this->createMock(IMimeTypeDetector::class);
 		$this->previewManager = $this->createMock(IPreview::class);
+		$this->userSession = $this->createMock(IUserSession::class);
+		$this->userSession->expects($this->any())
+			->method('getUser')
+			->willReturn($user);
+		$this->versionManager = $this->createMock(IVersionManager::class);
 
 		$this->controller = new PreviewController(
 			'files_versions',
 			$this->createMock(IRequest::class),
 			$this->rootFolder,
-			$this->userId,
+			$this->userSession,
 			$this->mimeTypeDetector,
+			$this->versionManager,
 			$this->previewManager
 		);
 	}
@@ -102,24 +123,23 @@ class PreviewControllerTest extends TestCase {
 	public function testValidPreview() {
 		$userFolder = $this->createMock(Folder::class);
 		$userRoot = $this->createMock(Folder::class);
-		$versions = $this->createMock(Folder::class);
 
 		$this->rootFolder->method('getUserFolder')
 			->with($this->userId)
 			->willReturn($userFolder);
 		$userFolder->method('getParent')
 			->willReturn($userRoot);
-		$userRoot->method('get')
-			->with('files_versions')
-			->willReturn($versions);
 
-		$this->mimeTypeDetector->method('detectPath')
-			->with($this->equalTo('file'))
-			->willReturn('myMime');
+		$sourceFile = $this->createMock(File::class);
+		$userFolder->method('get')
+			->with('file')
+			->willReturn($sourceFile);
 
 		$file = $this->createMock(File::class);
-		$versions->method('get')
-			->with($this->equalTo('file.v42'))
+		$file->method('getMimetype')
+			->willReturn('myMime');
+
+		$this->versionManager->method('getVersionFile')
 			->willReturn($file);
 
 		$preview = $this->createMock(ISimpleFile::class);
@@ -138,24 +158,23 @@ class PreviewControllerTest extends TestCase {
 	public function testVersionNotFound() {
 		$userFolder = $this->createMock(Folder::class);
 		$userRoot = $this->createMock(Folder::class);
-		$versions = $this->createMock(Folder::class);
 
 		$this->rootFolder->method('getUserFolder')
 			->with($this->userId)
 			->willReturn($userFolder);
 		$userFolder->method('getParent')
 			->willReturn($userRoot);
-		$userRoot->method('get')
-			->with('files_versions')
-			->willReturn($versions);
+
+		$sourceFile = $this->createMock(File::class);
+		$userFolder->method('get')
+			->with('file')
+			->willReturn($sourceFile);
 
 		$this->mimeTypeDetector->method('detectPath')
 			->with($this->equalTo('file'))
 			->willReturn('myMime');
 
-		$file = $this->createMock(File::class);
-		$versions->method('get')
-			->with($this->equalTo('file.v42'))
+		$this->versionManager->method('getVersionFile')
 			->willThrowException(new NotFoundException());
 
 		$res = $this->controller->getPreview('file', 10, 10, '42');
diff --git a/resources/app-info.xsd b/resources/app-info.xsd
index fa06752c01d8b7c952837d57b0c1324e933b8bd7..287ed6b99135161263b96034bd1ec808bd0e4b2f 100644
--- a/resources/app-info.xsd
+++ b/resources/app-info.xsd
@@ -63,6 +63,8 @@
                             maxOccurs="1" />
                 <xs:element name="trash" type="trash" minOccurs="0"
                             maxOccurs="1" />
+                <xs:element name="versions" type="versions" minOccurs="0"
+                            maxOccurs="1" />
             </xs:sequence>
         </xs:complexType>
         <xs:unique name="uniqueNameL10n">
@@ -670,6 +672,21 @@
         </xs:simpleContent>
     </xs:complexType>
 
+    <xs:complexType name="versions">
+        <xs:sequence>
+            <xs:element name="backend" type="versions-backend" minOccurs="1"
+                        maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="versions-backend">
+        <xs:simpleContent>
+            <xs:extension base="php-class">
+                <xs:attribute name="for" type="php-class" use="required"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
     <xs:simpleType name="php-class">
         <xs:restriction base="xs:string">
             <xs:pattern