diff --git a/core/Migrations/Version15000Date20180917092725.php b/core/Migrations/Version15000Date20180917092725.php
new file mode 100644
index 0000000000000000000000000000000000000000..9dbc5efceda462bd936dfd09f2fd8b4bf0fe0811
--- /dev/null
+++ b/core/Migrations/Version15000Date20180917092725.php
@@ -0,0 +1,76 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
+ *
+ * @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 OC\Core\Migrations;
+
+use Closure;
+use Doctrine\DBAL\Types\Type;
+use OCP\DB\ISchemaWrapper;
+use OCP\Migration\SimpleMigrationStep;
+use OCP\Migration\IOutput;
+
+class Version15000Date20180917092725 extends SimpleMigrationStep {
+
+
+	/**
+	 * @param IOutput $output
+	 * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+	 * @param array $options
+	 * @return null|ISchemaWrapper
+	 */
+	public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
+		/** @var ISchemaWrapper $schema */
+		$schema = $schemaClosure();
+
+		if (!$schema->hasTable('collres_collections')) {
+			$table = $schema->createTable('collres_collections');
+
+			$table->addColumn('id', Type::BIGINT, [
+				'autoincrement' => true,
+				'notnull' => true,
+			]);
+
+			$table->setPrimaryKey(['id']);
+		}
+
+		if (!$schema->hasTable('collres_resources')) {
+			$table = $schema->createTable('collres_resources');
+
+			$table->addColumn('collection_id', Type::BIGINT, [
+				'notnull' => true,
+			]);
+			$table->addColumn('resource_type', Type::STRING, [
+				'notnull' => true,
+				'length' => 64,
+			]);
+			$table->addColumn('resource_id', Type::STRING, [
+				'notnull' => true,
+				'length' => 64,
+			]);
+
+			$table->addUniqueIndex(['collection_id', 'resource_type', 'resource_id'], 'collres_unique_res');
+		}
+
+		return $schema;
+	}
+
+}
diff --git a/lib/private/Collaboration/Resources/Collection.php b/lib/private/Collaboration/Resources/Collection.php
new file mode 100644
index 0000000000000000000000000000000000000000..8509b4442de5b84124d955ec47444934a3b38cc2
--- /dev/null
+++ b/lib/private/Collaboration/Resources/Collection.php
@@ -0,0 +1,155 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
+ *
+ * @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 OC\Collaboration\Resources;
+
+
+use Doctrine\DBAL\Exception\ConstraintViolationException;
+use OCP\Collaboration\Resources\IManager;
+use OCP\Collaboration\Resources\ResourceException;
+use OCP\Collaboration\Resources\ICollection;
+use OCP\Collaboration\Resources\IResource;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+
+class Collection implements ICollection {
+
+	/** @var IManager */
+	protected $manager;
+
+	/** @var IDBConnection */
+	protected $connection;
+
+	/** @var int */
+	protected $id;
+
+	/** @var IResource[] */
+	protected $resources;
+
+	public function __construct(IManager $manager, IDBConnection $connection, int $id) {
+		$this->manager = $manager;
+		$this->connection = $connection;
+		$this->id = $id;
+		$this->resources = [];
+	}
+
+	/**
+	 * @return IResource[]
+	 * @since 15.0.0
+	 */
+	public function getResources(): array {
+		if (empty($this->resources)) {
+			$query = $this->connection->getQueryBuilder();
+			$query->select('resource_type', 'resource_id')
+				->from('collres_resources')
+				->where($query->expr()->eq('collection_id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT)));
+
+			$result = $query->execute();
+			while ($row = $result->fetch()) {
+				$this->resources[] = $this->manager->getResource($row['resource_type'], $row['resource_id']);
+			}
+			$result->closeCursor();
+		}
+
+		return $this->resources;
+	}
+
+	/**
+	 * Adds a resource to a collection
+	 *
+	 * @param IResource $resource
+	 * @throws ResourceException when the resource is already part of the collection
+	 * @since 15.0.0
+	 */
+	public function addResource(IResource $resource) {
+		array_map(function(IResource $r) use ($resource) {
+			if ($this->isSameResource($r, $resource)) {
+				throw new ResourceException('Already part of the collection');
+			}
+		}, $this->resources);
+
+		$this->resources[] = $resource;
+
+		if ($this->id === 0) {
+			$this->makeCollectionPersistent();
+		}
+
+		$query = $this->connection->getQueryBuilder();
+		$query->insert('collres_resources')
+			->values([
+				'collection_id' => $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT),
+				'resource_type' => $query->createNamedParameter($resource->getType()),
+				'resource_id' => $query->createNamedParameter($resource->getId()),
+			]);
+
+		try {
+			$query->execute();
+		} catch (ConstraintViolationException $e) {
+			throw new ResourceException('Already part of the collection');
+		}
+	}
+
+	/**
+	 * Removes a resource from a collection
+	 *
+	 * @param IResource $resource
+	 * @since 15.0.0
+	 */
+	public function removeResource(IResource $resource) {
+		$this->resources = array_filter($this->resources, function(IResource $r) use ($resource) {
+			return !$this->isSameResource($r, $resource);
+		});
+
+		$query = $this->connection->getQueryBuilder();
+		$query->delete('collres_resources')
+			->where($query->expr()->eq('collection_id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT)))
+			->andWhere($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType())))
+			->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())));
+		$query->execute();
+
+		if (empty($this->resources)) {
+			$this->makeCollectionUnsteady();
+		}
+	}
+
+	protected function isSameResource(IResource $resource1, IResource $resource2): bool {
+		return $resource1->getType() === $resource2->getType() &&
+			$resource1->getId() === $resource2->getId();
+	}
+
+	protected function makeCollectionPersistent() {
+		$query = $this->connection->getQueryBuilder();
+		$query->insert('collres_collections');
+		$query->execute();
+
+		$this->id = $query->getLastInsertId();
+	}
+
+	protected function makeCollectionUnsteady() {
+		$query = $this->connection->getQueryBuilder();
+		$query->delete('collres_collections')
+			->where($query->expr()->eq('id', $query->createNamedParameter($this->id, IQueryBuilder::PARAM_INT)));
+		$query->execute();
+
+		$this->id = 0;
+	}
+}
diff --git a/lib/private/Collaboration/Resources/Manager.php b/lib/private/Collaboration/Resources/Manager.php
new file mode 100644
index 0000000000000000000000000000000000000000..e36c4ab1d38894ce2cab2526352dbd2b22877c2f
--- /dev/null
+++ b/lib/private/Collaboration/Resources/Manager.php
@@ -0,0 +1,58 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
+ *
+ * @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 OC\Collaboration\Resources;
+
+
+use OCP\Collaboration\Resources\ICollection;
+use OCP\Collaboration\Resources\IManager;
+use OCP\Collaboration\Resources\IResource;
+use OCP\IDBConnection;
+
+class Manager implements IManager {
+
+	/** @var IDBConnection */
+	protected $connection;
+
+	public function __construct(IDBConnection $connection) {
+		$this->connection = $connection;
+	}
+
+	/**
+	 * @param int $id
+	 * @return ICollection
+	 * @since 15.0.0
+	 */
+	public function getCollection(int $id): ICollection {
+		return new Collection($this, $this->connection, $id);
+	}
+
+	/**
+	 * @param string $type
+	 * @param string $id
+	 * @return IResource
+	 * @since 15.0.0
+	 */
+	public function getResource(string $type, string $id): IResource {
+		return new Resource($this, $this->connection, $type, $id);
+	}
+}
diff --git a/lib/private/Collaboration/Resources/Resource.php b/lib/private/Collaboration/Resources/Resource.php
new file mode 100644
index 0000000000000000000000000000000000000000..f82ceff5596dc715d86f1a982a29626d45e1b8e8
--- /dev/null
+++ b/lib/private/Collaboration/Resources/Resource.php
@@ -0,0 +1,91 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
+ *
+ * @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 OC\Collaboration\Resources;
+
+
+use OCP\Collaboration\Resources\ICollection;
+use OCP\Collaboration\Resources\IManager;
+use OCP\Collaboration\Resources\IResource;
+use OCP\IDBConnection;
+
+class Resource implements IResource {
+
+	/** @var IManager */
+	protected $manager;
+
+	/** @var IDBConnection */
+	protected $connection;
+
+	/** @var string */
+	protected $type;
+
+	/** @var string */
+	protected $id;
+
+	public function __construct(IManager $manager, IDBConnection $connection, string $type, string $id) {
+		$this->manager = $manager;
+		$this->connection = $connection;
+		$this->type = $type;
+		$this->id = $id;
+	}
+
+	/**
+	 * @return string
+	 * @since 15.0.0
+	 */
+	public function getType(): string {
+		return $this->type;
+	}
+
+	/**
+	 * @return string
+	 * @since 15.0.0
+	 */
+	public function getId(): string {
+		return $this->id;
+	}
+
+	/**
+	 * @param IResource $resource
+	 * @return ICollection[]
+	 * @since 15.0.0
+	 */
+	public function getCollections(IResource $resource): array {
+		$collections = [];
+
+		$query = $this->connection->getQueryBuilder();
+
+		$query->select('collection_id')
+			->from('collres_resources')
+			->where($query->expr()->eq('resource_type', $query->createNamedParameter($resource->getType())))
+			->andWhere($query->expr()->eq('resource_id', $query->createNamedParameter($resource->getId())));
+
+		$result = $query->execute();
+		while ($row = $result->fetch()) {
+			$collections[] = $this->manager->getCollection((int) $row['collection_id']);
+		}
+		$result->closeCursor();
+
+		return $collections;
+	}
+}
diff --git a/lib/public/Collaboration/Resources/ICollection.php b/lib/public/Collaboration/Resources/ICollection.php
new file mode 100644
index 0000000000000000000000000000000000000000..408ec67401aecaa97a5b5c3953bdda8bfd3c0d71
--- /dev/null
+++ b/lib/public/Collaboration/Resources/ICollection.php
@@ -0,0 +1,52 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
+ *
+ * @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 OCP\Collaboration\Resources;
+
+/**
+ * @since 15.0.0
+ */
+interface ICollection {
+
+	/**
+	 * @return IResource[]
+	 * @since 15.0.0
+	 */
+	public function getResources(): array;
+
+	/**
+	 * Adds a resource to a collection
+	 *
+	 * @param IResource $resource
+	 * @throws ResourceException when the resource is already part of the collection
+	 * @since 15.0.0
+	 */
+	public function addResource(IResource $resource);
+
+	/**
+	 * Removes a resource from a collection
+	 *
+	 * @param IResource $resource
+	 * @since 15.0.0
+	 */
+	public function removeResource(IResource $resource);
+}
diff --git a/lib/public/Collaboration/Resources/IManager.php b/lib/public/Collaboration/Resources/IManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..9a7fda28bb4f2c86ebfb6d92fce75431024f382f
--- /dev/null
+++ b/lib/public/Collaboration/Resources/IManager.php
@@ -0,0 +1,45 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
+ *
+ * @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 OCP\Collaboration\Resources;
+
+/**
+ * @since 15.0.0
+ */
+interface IManager extends IProvider {
+
+	/**
+	 * @param int $id
+	 * @return ICollection
+	 * @since 15.0.0
+	 */
+	public function getCollection(int $id): ICollection;
+
+	/**
+	 * @param string $type
+	 * @param string $id
+	 * @return IResource
+	 * @since 15.0.0
+	 */
+	public function getResource(string $type, string $id): IResource;
+
+}
diff --git a/lib/public/Collaboration/Resources/IProvider.php b/lib/public/Collaboration/Resources/IProvider.php
new file mode 100644
index 0000000000000000000000000000000000000000..06e2a6a81eec9216dffb3e8faa7bb65ea3f861b1
--- /dev/null
+++ b/lib/public/Collaboration/Resources/IProvider.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
+ *
+ * @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 OCP\Collaboration\Resources;
+
+
+interface IProvider {
+
+}
diff --git a/lib/public/Collaboration/Resources/IResource.php b/lib/public/Collaboration/Resources/IResource.php
new file mode 100644
index 0000000000000000000000000000000000000000..42631bc27a82e50ce884da0eabdddadfd3c2a35c
--- /dev/null
+++ b/lib/public/Collaboration/Resources/IResource.php
@@ -0,0 +1,48 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
+ *
+ * @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 OCP\Collaboration\Resources;
+
+/**
+ * @since 15.0.0
+ */
+interface IResource {
+
+	/**
+	 * @return string
+	 * @since 15.0.0
+	 */
+	public function getType(): string;
+
+	/**
+	 * @return string
+	 * @since 15.0.0
+	 */
+	public function getId(): string;
+
+	/**
+	 * @param IResource $resource
+	 * @return ICollection[]
+	 * @since 15.0.0
+	 */
+	public function getCollections(IResource $resource): array;
+}
diff --git a/lib/public/Collaboration/Resources/ResourceException.php b/lib/public/Collaboration/Resources/ResourceException.php
new file mode 100644
index 0000000000000000000000000000000000000000..f31b2031a89c9c73a217e5922715ff62350c9160
--- /dev/null
+++ b/lib/public/Collaboration/Resources/ResourceException.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @copyright Copyright (c) 2018 Joas Schilling <coding@schilljs.com>
+ *
+ * @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 OCP\Collaboration\Resources;
+
+
+class ResourceException extends \RuntimeException {
+
+}