diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index 77d35d2a1..171c6d43b 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -104,9 +104,10 @@ jobs:
           ./occ news:generate-explore --votes 100 "https://nextcloud.com/blog/feed/"
           ./occ news:folder:add 'admin' 'Something'
           ./occ news:folder:list 'admin' | grep 'Something'
-          ./occ news:folder:delete 'admin' $(./occ news:folder:list 'admin' | grep 'Something' -1  | head -1 | grep -oE '[0-9]*')
           ./occ news:feed:add 'admin' "https://nextcloud.com/blog/feed/"
           ./occ news:feed:list 'admin' | grep 'nextcloud\.com'
+          ./occ news:opml:export 'admin' | grep 'nextcloud\.com'
+          ./occ news:folder:delete 'admin' $(./occ news:folder:list 'admin' | grep 'Something' -1  | head -1 | grep -oE '[0-9]*')
           ./occ news:feed:delete 'admin' $(./occ news:feed:list 'admin' | grep 'nextcloud\.com' -1  | head -1 | grep -oE '[0-9]*')
 
       - name: Prep PHP tests
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ee244d80b..f48f0c469 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,21 @@ All notable changes to this project will be documented in this file.
 
 ## Unreleased
 
+- Drop support before nextcloud 20
+- Move to modern SQL syntax
+- Add management commands
+```shell script
+./occ news:opml:export <userID>
+
+./occ news:folder:add <userID> <name>
+./occ news:folder:list <userID>
+./occ news:folder:delete <userID>
+
+./occ news:feed:add <userID> <URL>
+./occ news:feed:list <userID>
+./occ news:feed:delete <userID>
+```
+
 ## 14.2.2
 
 ### Changed
@@ -99,7 +114,7 @@ All notable changes to this project will be documented in this file.
 ## 14.1.2
 
 ## Changed
-- Updated js packages 
+- Updated js packages
 
 ### Fixed
 - Signature was missing
@@ -163,7 +178,7 @@ All notable changes to this project will be documented in this file.
 ### Fixed
 - Fixed some feeds with a empty body #474
 - Restored full text by default for some feeds #479
-- Some smaller adjustments for the design #463 #464 
+- Some smaller adjustments for the design #463 #464
 
 ## 13.1.4
 
@@ -187,7 +202,7 @@ All notable changes to this project will be documented in this file.
 - Highlight in compact mode #109
 - Prevent raw angluar templates from flashing on page load #429
 - HTML elements where not rendered #428
-- Provide UserAgent to prevent HTTP 403 errors #428 
+- Provide UserAgent to prevent HTTP 403 errors #428
 
 ## 13.1.1
 
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 86c848d65..9297fa5e8 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -65,11 +65,12 @@ Before you update to a new version, [check the changelog](https://github.com/nex
         <command>OCA\News\Command\Config\FeedAdd</command>
         <command>OCA\News\Command\Config\FeedDelete</command>
         <command>OCA\News\Command\Config\FeedDelete</command>
+        <command>OCA\News\Command\Config\OpmlExport</command>
     </commands>
 
     <settings>
-        <admin>OCA\News\Settings\Admin</admin>
-        <admin-section>OCA\News\Settings\Section</admin-section>
+        <admin>OCA\News\Settings\AdminSettings</admin>
+        <admin-section>OCA\News\Settings\AdminSection</admin-section>
     </settings>
 
     <navigations>
diff --git a/composer.json b/composer.json
index a5cbc622e..a5a00775f 100644
--- a/composer.json
+++ b/composer.json
@@ -51,7 +51,8 @@
     "ext-json": "*",
     "ext-simplexml": "*",
     "ext-libxml": "*",
-    "ext-dom": "*"
+    "ext-dom": "*",
+    "ext-curl": "*"
   },
   "require-dev": {
     "phpunit/phpunit": "9.2.*",
diff --git a/composer.lock b/composer.lock
index f305f3294..5078effa1 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "e553641d7a0ca7ff73af7bdbc2c47617",
+    "content-hash": "63f7665291caac91a887b6eb20a03db7",
     "packages": [
         {
             "name": "andreskrey/readability.php",
@@ -2298,7 +2298,8 @@
         "ext-json": "*",
         "ext-simplexml": "*",
         "ext-libxml": "*",
-        "ext-dom": "*"
+        "ext-dom": "*",
+        "ext-curl": "*"
     },
     "platform-dev": [],
     "plugin-api-version": "1.1.0"
diff --git a/lib/Command/Config/OpmlExport.php b/lib/Command/Config/OpmlExport.php
new file mode 100644
index 000000000..1642e8505
--- /dev/null
+++ b/lib/Command/Config/OpmlExport.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace OCA\News\Command\Config;
+
+use OCA\News\Service\OpmlService;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class OpmlExport extends Command
+{
+    /**
+     * @var OpmlService service for the data.
+     */
+    protected $opmlService;
+
+    public function __construct(OpmlService $opmlService)
+    {
+        parent::__construct(null);
+
+        $this->opmlService = $opmlService;
+    }
+
+    /**
+     * Configure command
+     */
+    protected function configure()
+    {
+        $this->setName('news:opml:export')
+            ->setDescription('Print OPML file')
+            ->addArgument('userID', InputArgument::REQUIRED, 'User data to export');
+    }
+
+    /**
+     * Execute command
+     *
+     * @param InputInterface  $input
+     * @param OutputInterface $output
+     *
+     * @return int|void
+     */
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        $user = $input->getArgument('userID');
+
+        $output->write($this->opmlService->export($user));
+        return 0;
+    }
+}
diff --git a/lib/Command/ShowFeed.php b/lib/Command/ShowFeed.php
index 1218279e6..8aace3528 100644
--- a/lib/Command/ShowFeed.php
+++ b/lib/Command/ShowFeed.php
@@ -50,6 +50,9 @@ class ShowFeed extends Command
         $this->feedFetcher  = $feedFetcher;
     }
 
+    /**
+     * Configure the command
+     */
     protected function configure()
     {
         $this->setName('news:show-feed')
@@ -60,6 +63,14 @@ class ShowFeed extends Command
             ->addOption('full-text', 'f', InputOption::VALUE_NONE, 'Usa a scraper to get full text');
     }
 
+    /**
+     * Execute the command
+     *
+     * @param InputInterface  $input
+     * @param OutputInterface $output
+     *
+     * @return int
+     */
     protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $url   = $input->getArgument('feed');
diff --git a/lib/Config/FetcherConfig.php b/lib/Config/FetcherConfig.php
index 4966f5b40..3e75d854a 100644
--- a/lib/Config/FetcherConfig.php
+++ b/lib/Config/FetcherConfig.php
@@ -98,9 +98,9 @@ class FetcherConfig
     /**
      * Configure a guzzle client
      *
-     * @return ClientInterface Legacy client to guzzle.
+     * @return ClientInterface Client to guzzle.
      */
-    public function getClient()
+    public function getClient(): ClientInterface
     {
         $config = [
             'timeout' => $this->client_timeout,
diff --git a/lib/Controller/AdminController.php b/lib/Controller/AdminController.php
index addc53591..e3551a2a1 100644
--- a/lib/Controller/AdminController.php
+++ b/lib/Controller/AdminController.php
@@ -67,12 +67,17 @@ class AdminController extends Controller
      *
      * @return TemplateResponse
      */
-    public function index()
+    public function index(): TemplateResponse
     {
         return new TemplateResponse($this->appName, 'admin', $this->getData(), 'blank');
     }
 
-    private function getData()
+    /**
+     * Get admin data.
+     *
+     * @return array
+     */
+    private function getData(): array
     {
         $data = [];
 
@@ -108,7 +113,7 @@ class AdminController extends Controller
         bool $useCronUpdates,
         string $exploreUrl,
         int $updateInterval
-    ) {
+    ): array {
         $this->config->setAppValue($this->appName, 'autoPurgeMinimumInterval', $autoPurgeMinimumInterval);
         $this->config->setAppValue($this->appName, 'autoPurgeCount', $autoPurgeCount);
         $this->config->setAppValue($this->appName, 'maxRedirects', $maxRedirects);
diff --git a/lib/Controller/ApiController.php b/lib/Controller/ApiController.php
index 68caf9236..544b2c23b 100644
--- a/lib/Controller/ApiController.php
+++ b/lib/Controller/ApiController.php
@@ -16,6 +16,7 @@
 namespace OCA\News\Controller;
 
 use \OCP\IRequest;
+use OCP\IUser;
 use \OCP\IUserSession;
 use \OCP\AppFramework\ApiController as BaseApiController;
 
diff --git a/lib/Controller/EntityApiSerializer.php b/lib/Controller/EntityApiSerializer.php
index c7fdb84e5..daa0f20e5 100644
--- a/lib/Controller/EntityApiSerializer.php
+++ b/lib/Controller/EntityApiSerializer.php
@@ -57,7 +57,7 @@ class EntityApiSerializer
     }
 
 
-    private function convert($entities)
+    private function convert(array $entities)
     {
         $converted = [];
 
diff --git a/lib/Controller/ExportController.php b/lib/Controller/ExportController.php
index 16bdfbd4e..78f200934 100644
--- a/lib/Controller/ExportController.php
+++ b/lib/Controller/ExportController.php
@@ -13,39 +13,37 @@
 
 namespace OCA\News\Controller;
 
+use OCA\News\Service\FeedServiceV2;
+use OCA\News\Service\FolderServiceV2;
+use OCA\News\Service\ItemServiceV2;
+use OCA\News\Service\OpmlService;
+use OCP\AppFramework\Http\DataDownloadResponse;
 use \OCP\IRequest;
 use \OCP\AppFramework\Controller;
-use \OCP\AppFramework\Http;
 use \OCP\AppFramework\Http\JSONResponse;
 
-use \OCA\News\Http\TextDownloadResponse;
-use \OCA\News\Service\FolderService;
-use \OCA\News\Service\FeedService;
-use \OCA\News\Service\ItemService;
-use \OCA\News\Utility\OPMLExporter;
-
 class ExportController extends Controller
 {
 
-    private $opmlExporter;
+    private $opmlService;
     private $folderService;
     private $feedService;
     private $itemService;
     private $userId;
 
     public function __construct(
-        $appName,
+        string $appName,
         IRequest $request,
-        FolderService $folderService,
-        FeedService $feedService,
-        ItemService $itemService,
-        OPMLExporter $opmlExporter,
-        $UserId
+        FolderServiceV2 $folderService,
+        FeedServiceV2 $feedService,
+        ItemServiceV2 $itemService,
+        OpmlService $opmlService,
+        string $UserId
     ) {
         parent::__construct($appName, $request);
         $this->feedService = $feedService;
         $this->folderService = $folderService;
-        $this->opmlExporter = $opmlExporter;
+        $this->opmlService = $opmlService;
         $this->itemService = $itemService;
         $this->userId = $UserId;
     }
@@ -55,15 +53,15 @@ class ExportController extends Controller
      * @NoAdminRequired
      * @NoCSRFRequired
      */
-    public function opml()
+    public function opml(): DataDownloadResponse
     {
-        $feeds = $this->feedService->findAll($this->userId);
-        $folders = $this->folderService->findAll($this->userId);
-        $opml = $this->opmlExporter->build($folders, $feeds)->saveXML();
         $date = date('Y-m-d');
-        $name = "subscriptions-" . $date . ".opml";
-        $mimeType = 'text/xml';
-        return new TextDownloadResponse($opml, $name, $mimeType);
+
+        return new DataDownloadResponse(
+            $this->opmlService->export($this->userId),
+            "subscriptions-${date}.opml",
+            'text/xml'
+        );
     }
 
 
@@ -71,10 +69,10 @@ class ExportController extends Controller
      * @NoAdminRequired
      * @NoCSRFRequired
      */
-    public function articles()
+    public function articles(): JSONResponse
     {
-        $feeds = $this->feedService->findAll($this->userId);
-        $items = $this->itemService->getUnreadOrStarred($this->userId);
+        $feeds = $this->feedService->findAllForUser($this->userId);
+        $items = $this->itemService->findAllForUser($this->userId, ['unread' => true, 'starred' => true]);
 
         // build assoc array for fast access
         $feedsDict = [];
diff --git a/lib/Controller/FeedApiController.php b/lib/Controller/FeedApiController.php
index c0b4f1a56..cb3d5e645 100644
--- a/lib/Controller/FeedApiController.php
+++ b/lib/Controller/FeedApiController.php
@@ -18,6 +18,7 @@ namespace OCA\News\Controller;
 use OCA\News\Service\Exceptions\ServiceConflictException;
 use OCA\News\Service\Exceptions\ServiceNotFoundException;
 use OCA\News\Utility\PsrLogger;
+use OCP\AppFramework\Http\JSONResponse;
 use \OCP\IRequest;
 use \OCP\ILogger;
 use \OCP\IUserSession;
@@ -52,7 +53,7 @@ class FeedApiController extends ApiController
     private $serializer;
 
     public function __construct(
-        $appName,
+        string $appName,
         IRequest $request,
         IUserSession $userSession,
         FeedService $feedService,
@@ -72,7 +73,7 @@ class FeedApiController extends ApiController
      * @NoCSRFRequired
      * @CORS
      */
-    public function index()
+    public function index(): array
     {
 
         $result = [
@@ -100,9 +101,10 @@ class FeedApiController extends ApiController
      *
      * @param string $url
      * @param int    $folderId
-     * @return array|mixed|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|mixed|JSONResponse
      */
-    public function create($url, $folderId = 0)
+    public function create(string $url, int $folderId = 0)
     {
         try {
             $this->feedService->purgeDeleted($this->getUserId(), false);
@@ -133,9 +135,10 @@ class FeedApiController extends ApiController
      * @CORS
      *
      * @param int $feedId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function delete($feedId)
+    public function delete(int $feedId)
     {
         try {
             $this->feedService->delete($feedId, $this->getUserId());
@@ -155,7 +158,7 @@ class FeedApiController extends ApiController
      * @param int $feedId
      * @param int $newestItemId
      */
-    public function read($feedId, $newestItemId)
+    public function read(int $feedId, int $newestItemId): void
     {
         $this->itemService->readFeed($feedId, $newestItemId, $this->getUserId());
     }
@@ -168,9 +171,10 @@ class FeedApiController extends ApiController
      *
      * @param int $feedId
      * @param int $folderId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function move($feedId, $folderId)
+    public function move(int $feedId, int $folderId)
     {
         try {
             $this->feedService->patch(
@@ -193,9 +197,10 @@ class FeedApiController extends ApiController
      *
      * @param int    $feedId
      * @param string $feedTitle
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function rename($feedId, $feedTitle)
+    public function rename(int $feedId, string $feedTitle)
     {
         try {
             $this->feedService->patch(
@@ -215,7 +220,7 @@ class FeedApiController extends ApiController
      * @NoCSRFRequired
      * @CORS
      */
-    public function fromAllUsers()
+    public function fromAllUsers(): array
     {
         $feeds = $this->feedService->findAllFromAllUsers();
         $result = ['feeds' => []];
@@ -237,7 +242,7 @@ class FeedApiController extends ApiController
      * @param string $userId
      * @param int    $feedId
      */
-    public function update($userId, $feedId)
+    public function update(string $userId, int $feedId): void
     {
         try {
             $this->feedService->update($userId, $feedId);
diff --git a/lib/Controller/FeedController.php b/lib/Controller/FeedController.php
index d0c25d55b..c09096bd9 100644
--- a/lib/Controller/FeedController.php
+++ b/lib/Controller/FeedController.php
@@ -15,6 +15,7 @@ namespace OCA\News\Controller;
 
 use OCA\News\Service\Exceptions\ServiceConflictException;
 use OCA\News\Service\Exceptions\ServiceNotFoundException;
+use OCP\AppFramework\Http\JSONResponse;
 use OCP\IRequest;
 use OCP\IConfig;
 use OCP\AppFramework\Controller;
@@ -36,13 +37,13 @@ class FeedController extends Controller
     private $settings;
 
     public function __construct(
-        $appName,
+        string $appName,
         IRequest $request,
         FolderService $folderService,
         FeedService $feedService,
         ItemService $itemService,
         IConfig $settings,
-        $UserId
+        string $UserId
     ) {
         parent::__construct($appName, $request);
         $this->feedService = $feedService;
@@ -56,7 +57,7 @@ class FeedController extends Controller
     /**
      * @NoAdminRequired
      */
-    public function index()
+    public function index(): array
     {
 
         // this method is also used to update the interface
@@ -83,7 +84,7 @@ class FeedController extends Controller
     /**
      * @NoAdminRequired
      */
-    public function active()
+    public function active(): array
     {
         $feedId = (int) $this->settings->getUserValue(
             $this->userId,
@@ -134,14 +135,15 @@ class FeedController extends Controller
      * @param string $title
      * @param string $user
      * @param string $password
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
     public function create(
-        $url,
-        $parentFolderId,
-        $title = null,
-        $user = null,
-        $password = null
+        string $url,
+        int $parentFolderId,
+        ?string $title = null,
+        ?string $user = null,
+        ?string $password = null
     ) {
         try {
             // we need to purge deleted feeds if a feed is created to
@@ -180,9 +182,10 @@ class FeedController extends Controller
      * @NoAdminRequired
      *
      * @param int $feedId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function delete($feedId)
+    public function delete(int $feedId)
     {
         try {
             $this->feedService->markDeleted($feedId, $this->userId);
@@ -198,9 +201,10 @@ class FeedController extends Controller
      * @NoAdminRequired
      *
      * @param int $feedId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function update($feedId)
+    public function update(int $feedId)
     {
         try {
             $feed = $this->feedService->update($this->userId, $feedId);
@@ -227,7 +231,7 @@ class FeedController extends Controller
      * @param array $json
      * @return array
      */
-    public function import($json)
+    public function import(array $json): array
     {
         $feed = $this->feedService->importArticles($json, $this->userId);
 
@@ -250,7 +254,7 @@ class FeedController extends Controller
      * @param int $highestItemId
      * @return array
      */
-    public function read($feedId, $highestItemId)
+    public function read(int $feedId, int $highestItemId): array
     {
         $this->itemService->readFeed($feedId, $highestItemId, $this->userId);
 
@@ -269,9 +273,10 @@ class FeedController extends Controller
      * @NoAdminRequired
      *
      * @param int $feedId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function restore($feedId)
+    public function restore(int $feedId)
     {
         try {
             $this->feedService->unmarkDeleted($feedId, $this->userId);
@@ -292,15 +297,17 @@ class FeedController extends Controller
      * @param int    $ordering
      * @param int    $folderId
      * @param string $title
+     *
+     * @return array|JSONResponse
      */
     public function patch(
-        $feedId,
-        $pinned = null,
-        $fullTextEnabled = null,
-        $updateMode = null,
-        $ordering = null,
-        $title = null,
-        $folderId = null
+        int $feedId,
+        ?bool $pinned = null,
+        ?bool $fullTextEnabled = null,
+        ?int $updateMode = null,
+        ?int $ordering = null,
+        ?int $folderId = null,
+        ?string $title = null
     ) {
         $attributes = [
             'pinned' => $pinned,
diff --git a/lib/Controller/FolderApiController.php b/lib/Controller/FolderApiController.php
index ff61f3300..1f79d7cf9 100644
--- a/lib/Controller/FolderApiController.php
+++ b/lib/Controller/FolderApiController.php
@@ -15,6 +15,7 @@
 
 namespace OCA\News\Controller;
 
+use OCP\AppFramework\Http\JSONResponse;
 use \OCP\IRequest;
 use \OCP\IUserSession;
 use \OCP\AppFramework\Http;
@@ -34,7 +35,7 @@ class FolderApiController extends ApiController
     private $serializer;
 
     public function __construct(
-        $appName,
+        string $appName,
         IRequest $request,
         IUserSession $userSession,
         FolderService $folderService,
@@ -55,7 +56,7 @@ class FolderApiController extends ApiController
     public function index()
     {
         return $this->serializer->serialize(
-            $this->folderService->findAll($this->getUserId())
+            $this->folderService->findAllForUser($this->getUserId())
         );
     }
 
@@ -66,9 +67,10 @@ class FolderApiController extends ApiController
      * @CORS
      *
      * @param string $name
-     * @return array|mixed|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|mixed|JSONResponse
      */
-    public function create($name)
+    public function create(string $name)
     {
         try {
             $this->folderService->purgeDeleted($this->getUserId(), false);
@@ -89,9 +91,10 @@ class FolderApiController extends ApiController
      * @CORS
      *
      * @param int $folderId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function delete($folderId)
+    public function delete(int $folderId)
     {
         try {
             $this->folderService->delete($folderId, $this->getUserId());
@@ -107,11 +110,13 @@ class FolderApiController extends ApiController
      * @NoAdminRequired
      * @NoCSRFRequired
      * @CORS
+     *
      * @param int    $folderId
      * @param string $name
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function update($folderId, $name)
+    public function update(int $folderId, string $name)
     {
         try {
             $this->folderService->rename($folderId, $name, $this->getUserId());
@@ -135,7 +140,7 @@ class FolderApiController extends ApiController
      * @param int $folderId
      * @param int $newestItemId
      */
-    public function read($folderId, $newestItemId)
+    public function read(int $folderId, int $newestItemId): void
     {
         $this->itemService->readFolder($folderId, $newestItemId, $this->getUserId());
     }
diff --git a/lib/Controller/FolderController.php b/lib/Controller/FolderController.php
index 38c580ff0..d19726963 100644
--- a/lib/Controller/FolderController.php
+++ b/lib/Controller/FolderController.php
@@ -13,6 +13,8 @@
 
 namespace OCA\News\Controller;
 
+use OCA\News\Service\Exceptions\ServiceException;
+use OCP\AppFramework\Http\JSONResponse;
 use \OCP\IRequest;
 use \OCP\AppFramework\Controller;
 use \OCP\AppFramework\Http;
@@ -34,7 +36,7 @@ class FolderController extends Controller
     private $userId;
 
     public function __construct(
-        $appName,
+        string $appName,
         IRequest $request,
         FolderService $folderService,
         FeedService $feedService,
@@ -54,7 +56,7 @@ class FolderController extends Controller
      */
     public function index()
     {
-        $folders = $this->folderService->findAll($this->userId);
+        $folders = $this->folderService->findAllForUser($this->userId);
         return ['folders' => $folders];
     }
 
@@ -64,13 +66,14 @@ class FolderController extends Controller
      *
      * @param int  $folderId
      * @param bool $open
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function open($folderId, $open)
+    public function open(int $folderId, bool $open)
     {
         try {
             $this->folderService->open($folderId, $open, $this->userId);
-        } catch (ServiceNotFoundException $ex) {
+        } catch (ServiceException $ex) {
             return $this->error($ex, Http::STATUS_NOT_FOUND);
         }
 
@@ -82,9 +85,10 @@ class FolderController extends Controller
      * @NoAdminRequired
      *
      * @param string $folderName
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function create($folderName)
+    public function create(string $folderName)
     {
         try {
             // we need to purge deleted folders if a folder is created to
@@ -105,9 +109,10 @@ class FolderController extends Controller
      * @NoAdminRequired
      *
      * @param int $folderId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function delete($folderId)
+    public function delete(int $folderId)
     {
         try {
             $this->folderService->markDeleted($folderId, $this->userId);
@@ -124,9 +129,10 @@ class FolderController extends Controller
      *
      * @param string $folderName
      * @param int    $folderId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function rename($folderName, $folderId)
+    public function rename(string $folderName, int $folderId)
     {
         try {
             $folder = $this->folderService->rename(
@@ -152,7 +158,7 @@ class FolderController extends Controller
      * @param int $highestItemId
      * @return array
      */
-    public function read($folderId, $highestItemId)
+    public function read(int $folderId, int $highestItemId): array
     {
         $this->itemService->readFolder(
             $folderId,
@@ -160,7 +166,7 @@ class FolderController extends Controller
             $this->userId
         );
 
-        return ['feeds' => $this->feedService->findAll($this->userId)];
+        return ['feeds' => $this->feedService->findAllForUser($this->userId)];
     }
 
 
@@ -168,9 +174,10 @@ class FolderController extends Controller
      * @NoAdminRequired
      *
      * @param int $folderId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function restore($folderId)
+    public function restore(int $folderId)
     {
         try {
             $this->folderService->unmarkDeleted($folderId, $this->userId);
diff --git a/lib/Controller/ItemApiController.php b/lib/Controller/ItemApiController.php
index dac2b0a5f..0ac0a890a 100644
--- a/lib/Controller/ItemApiController.php
+++ b/lib/Controller/ItemApiController.php
@@ -15,6 +15,7 @@
 
 namespace OCA\News\Controller;
 
+use OCP\AppFramework\Http\JSONResponse;
 use \OCP\IRequest;
 use \OCP\IUserSession;
 use \OCP\AppFramework\Http;
@@ -30,7 +31,7 @@ class ItemApiController extends ApiController
     private $serializer;
 
     public function __construct(
-        $appName,
+        string $appName,
         IRequest $request,
         IUserSession $userSession,
         ItemService $itemService
@@ -55,15 +56,15 @@ class ItemApiController extends ApiController
      * @return array|mixed
      */
     public function index(
-        $type = 3,
-        $id = 0,
-        $getRead = true,
-        $batchSize = -1,
-        $offset = 0,
-        $oldestFirst = false
+        int $type = 3,
+        int $id = 0,
+        bool $getRead = true,
+        int $batchSize = -1,
+        int $offset = 0,
+        bool $oldestFirst = false
     ) {
         return $this->serializer->serialize(
-            $this->itemService->findAll(
+            $this->itemService->findAllItems(
                 $id,
                 $type,
                 $batchSize,
@@ -124,9 +125,10 @@ class ItemApiController extends ApiController
      * @CORS
      *
      * @param int $itemId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function read($itemId)
+    public function read(int $itemId)
     {
         return $this->setRead(true, $itemId);
     }
@@ -138,9 +140,10 @@ class ItemApiController extends ApiController
      * @CORS
      *
      * @param int $itemId
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function unread($itemId)
+    public function unread(int $itemId)
     {
         return $this->setRead(false, $itemId);
     }
@@ -170,9 +173,10 @@ class ItemApiController extends ApiController
      *
      * @param int    $feedId
      * @param string $guidHash
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function star($feedId, $guidHash)
+    public function star(int $feedId, string $guidHash)
     {
         return $this->setStarred(true, $feedId, $guidHash);
     }
@@ -185,9 +189,10 @@ class ItemApiController extends ApiController
      *
      * @param int    $feedId
      * @param string $guidHash
-     * @return array|\OCP\AppFramework\Http\JSONResponse
+     *
+     * @return array|JSONResponse
      */
-    public function unstar($feedId, $guidHash)
+    public function unstar(int $feedId, string $guidHash)
     {
         return $this->setStarred(false, $feedId, $guidHash);
     }
@@ -200,7 +205,7 @@ class ItemApiController extends ApiController
      *
      * @param int $newestItemId
      */
-    public function readAll($newestItemId)
+    public function readAll(int $newestItemId)
     {
         $this->itemService->readAll($newestItemId, $this->getUserId());
     }
@@ -225,7 +230,7 @@ class ItemApiController extends ApiController
      *
      * @param int[] $items item ids
      */
-    public function readMultiple($items)
+    public function readMultiple(array $items)
     {
         $this->setMultipleRead(true, $items);
     }
@@ -238,7 +243,7 @@ class ItemApiController extends ApiController
      *
      * @param int[] $items item ids
      */
-    public function unreadMultiple($items)
+    public function unreadMultiple(array $items)
     {
         $this->setMultipleRead(false, $items);
     }
@@ -268,7 +273,7 @@ class ItemApiController extends ApiController
      *
      * @param int[] $items item ids
      */
-    public function starMultiple($items)
+    public function starMultiple(array $items)
     {
         $this->setMultipleStarred(true, $items);
     }
@@ -281,7 +286,7 @@ class ItemApiController extends ApiController
      *
      * @param int[] $items item ids
      */
-    public function unstarMultiple($items)
+    public function unstarMultiple(array $items)
     {
         $this->setMultipleStarred(false, $items);
     }
diff --git a/lib/Controller/ItemController.php b/lib/Controller/ItemController.php
index 95a13ee21..37d34e8ca 100644
--- a/lib/Controller/ItemController.php
+++ b/lib/Controller/ItemController.php
@@ -61,13 +61,13 @@ class ItemController extends Controller
      * @return array
      */
     public function index(
-        $type = 3,
-        $id = 0,
-        $limit = 50,
-        $offset = 0,
-        $showAll = null,
-        $oldestFirst = null,
-        $search = ''
+        int $type = 3,
+        int $id = 0,
+        int $limit = 50,
+        int $offset = 0,
+        ?bool $showAll = null,
+        ?bool $oldestFirst = null,
+        string $search = ''
     ) {
 
         // in case this is called directly and not from the website use the
@@ -119,12 +119,12 @@ class ItemController extends Controller
             if ($offset === 0) {
                 $params['newestItemId'] =
                     $this->itemService->getNewestItemId($this->userId);
-                $params['feeds'] = $this->feedService->findAll($this->userId);
+                $params['feeds'] = $this->feedService->findAllForUser($this->userId);
                 $params['starred'] =
                     $this->itemService->starredCount($this->userId);
             }
 
-            $params['items'] = $this->itemService->findAll(
+            $params['items'] = $this->itemService->findAllItems(
                 $id,
                 $type,
                 $limit,
@@ -165,7 +165,7 @@ class ItemController extends Controller
         try {
             $params['newestItemId'] =
                 $this->itemService->getNewestItemId($this->userId);
-            $params['feeds'] = $this->feedService->findAll($this->userId);
+            $params['feeds'] = $this->feedService->findAllForUser($this->userId);
             $params['starred'] =
                 $this->itemService->starredCount($this->userId);
             $params['items'] = $this->itemService->findAllNew(
@@ -238,7 +238,7 @@ class ItemController extends Controller
     public function readAll($highestItemId)
     {
         $this->itemService->readAll($highestItemId, $this->userId);
-        return ['feeds' => $this->feedService->findAll($this->userId)];
+        return ['feeds' => $this->feedService->findAllForUser($this->userId)];
     }
 
 
diff --git a/lib/Controller/JSONHttpErrorTrait.php b/lib/Controller/JSONHttpErrorTrait.php
index 785f3f02a..e3e343f16 100644
--- a/lib/Controller/JSONHttpErrorTrait.php
+++ b/lib/Controller/JSONHttpErrorTrait.php
@@ -20,7 +20,7 @@ trait JSONHttpErrorTrait
      * @param int        $code      The http error code
      * @return JSONResponse
      */
-    public function error(\Exception $exception, $code)
+    public function error(\Exception $exception, int $code)
     {
         return new JSONResponse(['message' => $exception->getMessage()], $code);
     }
diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php
index ffcf2e62d..2b20d4695 100644
--- a/lib/Controller/PageController.php
+++ b/lib/Controller/PageController.php
@@ -87,7 +87,7 @@ class PageController extends Controller
      * @NoAdminRequired
      * @NoCSRFRequired
      */
-    public function index()
+    public function index(): TemplateResponse
     {
         $status = $this->statusService->getStatus();
         $response = new TemplateResponse(
@@ -118,7 +118,7 @@ class PageController extends Controller
     /**
      * @NoAdminRequired
      */
-    public function settings()
+    public function settings(): array
     {
         $settings = [
             'showAll',
@@ -173,7 +173,7 @@ class PageController extends Controller
         bool $preventReadOnScroll,
         bool $oldestFirst,
         bool $compactExpand
-    ) {
+    ): void {
         $settings = [
             'showAll'             => $showAll,
             'compact'             => $compact,
diff --git a/lib/Controller/UserApiController.php b/lib/Controller/UserApiController.php
index 1a5f34f70..b644ba1f0 100644
--- a/lib/Controller/UserApiController.php
+++ b/lib/Controller/UserApiController.php
@@ -24,11 +24,10 @@ use \OCP\AppFramework\Http;
 class UserApiController extends ApiController
 {
 
-    private $userSession;
     private $rootFolder;
 
     public function __construct(
-        $appName,
+        string $appName,
         IRequest $request,
         IUserSession $userSession,
         IRootFolder $rootFolder
@@ -42,7 +41,7 @@ class UserApiController extends ApiController
      * @NoCSRFRequired
      * @CORS
      */
-    public function index()
+    public function index(): array
     {
         $user = $this->getUser();
 
diff --git a/lib/Controller/UtilityApiController.php b/lib/Controller/UtilityApiController.php
index 23956f149..a2e5ae910 100644
--- a/lib/Controller/UtilityApiController.php
+++ b/lib/Controller/UtilityApiController.php
@@ -30,7 +30,7 @@ class UtilityApiController extends ApiController
     private $statusService;
 
     public function __construct(
-        $appName,
+        string $appName,
         IRequest $request,
         IUserSession $userSession,
         UpdaterService $updater,
diff --git a/lib/Db/EntityJSONSerializer.php b/lib/Db/EntityJSONSerializer.php
index 3afc18202..2646ed97a 100644
--- a/lib/Db/EntityJSONSerializer.php
+++ b/lib/Db/EntityJSONSerializer.php
@@ -16,8 +16,14 @@ namespace OCA\News\Db;
 trait EntityJSONSerializer
 {
 
-
-    public function serializeFields($properties)
+    /**
+     * Serialize object properties.
+     *
+     * @param array $properties Serializable properties
+     *
+     * @return array
+     */
+    public function serializeFields(array $properties): array
     {
         $result = [];
         foreach ($properties as $property) {
diff --git a/lib/Db/Feed.php b/lib/Db/Feed.php
index ae01c3d6c..9af2f7dc2 100644
--- a/lib/Db/Feed.php
+++ b/lib/Db/Feed.php
@@ -95,7 +95,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @return string|null
      */
-    public function getBasicAuthPassword()
+    public function getBasicAuthPassword(): ?string
     {
         return $this->basicAuthPassword;
     }
@@ -103,7 +103,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @return string|null
      */
-    public function getBasicAuthUser()
+    public function getBasicAuthUser(): ?string
     {
         return $this->basicAuthUser;
     }
@@ -111,7 +111,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @return int|null
      */
-    public function getDeletedAt()
+    public function getDeletedAt(): ?int
     {
         return $this->deletedAt;
     }
@@ -119,7 +119,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @return string|null
      */
-    public function getFaviconLink()
+    public function getFaviconLink(): ?string
     {
         return $this->faviconLink;
     }
@@ -167,7 +167,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @return string|null
      */
-    public function getLastModified()
+    public function getLastModified(): ?string
     {
         return $this->lastModified;
     }
@@ -175,7 +175,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @return string|null
      */
-    public function getLastUpdateError()
+    public function getLastUpdateError(): ?string
     {
         return $this->lastUpdateError;
     }
@@ -183,7 +183,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @return string|null
      */
-    public function getLink()
+    public function getLink(): ?string
     {
         return $this->link;
     }
@@ -191,7 +191,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @return string|null
      */
-    public function getLocation()
+    public function getLocation(): ?string
     {
         return $this->location;
     }
@@ -321,7 +321,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param int|null $added
      */
-    public function setAdded(int $added = null): Feed
+    public function setAdded(?int $added = null): Feed
     {
         if ($this->added !== $added) {
             $this->added = $added;
@@ -347,7 +347,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param string|null $basicAuthPassword
      */
-    public function setBasicAuthPassword(string $basicAuthPassword = null): Feed
+    public function setBasicAuthPassword(?string $basicAuthPassword = null): Feed
     {
         if ($this->basicAuthPassword !== $basicAuthPassword) {
             $this->basicAuthPassword = $basicAuthPassword;
@@ -360,7 +360,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param string|null $basicAuthUser
      */
-    public function setBasicAuthUser(string $basicAuthUser = null): Feed
+    public function setBasicAuthUser(?string $basicAuthUser = null): Feed
     {
         if ($this->basicAuthUser !== $basicAuthUser) {
             $this->basicAuthUser = $basicAuthUser;
@@ -373,7 +373,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param int|null $deletedAt
      */
-    public function setDeletedAt(int $deletedAt = null): Feed
+    public function setDeletedAt(?int $deletedAt = null): Feed
     {
         if ($this->deletedAt !== $deletedAt) {
             $this->deletedAt = $deletedAt;
@@ -386,7 +386,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param string|null $faviconLink
      */
-    public function setFaviconLink(string $faviconLink = null): Feed
+    public function setFaviconLink(?string $faviconLink = null): Feed
     {
         if ($this->faviconLink !== $faviconLink) {
             $this->faviconLink = $faviconLink;
@@ -425,7 +425,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param string|null $httpEtag
      */
-    public function setHttpEtag(string $httpEtag = null): Feed
+    public function setHttpEtag(?string $httpEtag = null): Feed
     {
         if ($this->httpEtag !== $httpEtag) {
             $this->httpEtag = $httpEtag;
@@ -438,7 +438,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param string|null $httpLastModified
      */
-    public function setHttpLastModified(string $httpLastModified = null): Feed
+    public function setHttpLastModified(?string $httpLastModified = null): Feed
     {
         if ($this->httpLastModified !== $httpLastModified) {
             $this->httpLastModified = $httpLastModified;
@@ -464,7 +464,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param string|null $lastModified
      */
-    public function setLastModified(string $lastModified = null): Feed
+    public function setLastModified(?string $lastModified = null): Feed
     {
         if ($this->lastModified !== $lastModified) {
             $this->lastModified = $lastModified;
@@ -477,7 +477,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param string|null $lastUpdateError
      */
-    public function setLastUpdateError(string $lastUpdateError = null): Feed
+    public function setLastUpdateError(?string $lastUpdateError = null): Feed
     {
         if ($this->lastUpdateError !== $lastUpdateError) {
             $this->lastUpdateError = $lastUpdateError;
@@ -490,7 +490,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param string|null $link
      */
-    public function setLink(string $link = null): Feed
+    public function setLink(?string $link = null): Feed
     {
         $link = trim($link);
         if (strpos($link, 'http') === 0 && $this->link !== $link) {
@@ -504,7 +504,7 @@ class Feed extends Entity implements IAPI, \JsonSerializable
     /**
      * @param string|null $location
      */
-    public function setLocation(string $location = null): Feed
+    public function setLocation(?string $location = null): Feed
     {
         if ($this->location !== $location) {
             $this->location = $location;
diff --git a/lib/Db/FeedMapperV2.php b/lib/Db/FeedMapperV2.php
index 2b4ff8f10..a7edecd88 100644
--- a/lib/Db/FeedMapperV2.php
+++ b/lib/Db/FeedMapperV2.php
@@ -46,7 +46,7 @@ class FeedMapperV2 extends NewsMapperV2
      *
      * @return Entity[]
      */
-    public function findAllFromUser(string $userId): array
+    public function findAllFromUser(string $userId, array $params = []): array
     {
         $builder = $this->db->getQueryBuilder();
         $builder->addSelect('*')
diff --git a/lib/Db/Folder.php b/lib/Db/Folder.php
index 674c9fabc..eb3389546 100644
--- a/lib/Db/Folder.php
+++ b/lib/Db/Folder.php
@@ -37,7 +37,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
     /**
      * @return int|null
      */
-    public function getDeletedAt()
+    public function getDeletedAt(): ?int
     {
         return $this->deletedAt;
     }
@@ -50,7 +50,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
     /**
      * @return string|null
      */
-    public function getLastModified()
+    public function getLastModified(): ?string
     {
         return $this->lastModified;
     }
@@ -68,7 +68,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
     /**
      * @return int|null
      */
-    public function getParentId()
+    public function getParentId(): ?int
     {
         return $this->parentId;
     }
@@ -95,7 +95,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
         );
     }
 
-    public function setDeletedAt(int $deletedAt = null)
+    public function setDeletedAt(?int $deletedAt = null): void
     {
         if ($this->deletedAt !== $deletedAt) {
             $this->deletedAt = $deletedAt;
@@ -103,7 +103,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setId(int $id)
+    public function setId(int $id): void
     {
         if ($this->id !== $id) {
             $this->id = $id;
@@ -111,7 +111,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setLastModified(string $lastModified = null)
+    public function setLastModified(?string $lastModified = null): void
     {
 
         if ($this->lastModified !== $lastModified) {
@@ -120,7 +120,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setName(string $name)
+    public function setName(string $name): void
     {
         if ($this->name !== $name) {
             $this->name = $name;
@@ -128,7 +128,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setOpened(bool $opened)
+    public function setOpened(bool $opened): void
     {
         if ($this->opened !== $opened) {
             $this->opened = $opened;
@@ -136,7 +136,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setParentId(int $parentId = 0)
+    public function setParentId(int $parentId = 0): void
     {
         if ($this->parentId !== $parentId) {
             $this->parentId = $parentId;
@@ -144,7 +144,7 @@ class Folder extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setUserId(string $userId)
+    public function setUserId(string $userId): void
     {
         if ($this->userId !== $userId) {
             $this->userId = $userId;
diff --git a/lib/Db/FolderMapperV2.php b/lib/Db/FolderMapperV2.php
index d684e5af2..7d0536607 100644
--- a/lib/Db/FolderMapperV2.php
+++ b/lib/Db/FolderMapperV2.php
@@ -44,7 +44,7 @@ class FolderMapperV2 extends NewsMapperV2
      *
      * @return Entity[]
      */
-    public function findAllFromUser($userId): array
+    public function findAllFromUser(string $userId, array $params = []): array
     {
         $builder = $this->db->getQueryBuilder();
         $builder->select('*')
diff --git a/lib/Db/Item.php b/lib/Db/Item.php
index 7d3924597..322d12fed 100644
--- a/lib/Db/Item.php
+++ b/lib/Db/Item.php
@@ -103,7 +103,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         return $item;
     }
 
-    public function generateSearchIndex()
+    public function generateSearchIndex(): void
     {
         $this->setSearchIndex(
             mb_strtolower(
@@ -121,7 +121,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getAuthor()
+    public function getAuthor(): ?string
     {
         return $this->author;
     }
@@ -129,7 +129,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getBody()
+    public function getBody(): ?string
     {
         return $this->body;
     }
@@ -137,7 +137,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getContentHash()
+    public function getContentHash(): ?string
     {
         return $this->contentHash;
     }
@@ -145,7 +145,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getEnclosureLink()
+    public function getEnclosureLink(): ?string
     {
         return $this->enclosureLink;
     }
@@ -153,7 +153,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getMediaThumbnail()
+    public function getMediaThumbnail(): ?string
     {
         return $this->mediaThumbnail;
     }
@@ -161,7 +161,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getMediaDescription()
+    public function getMediaDescription(): ?string
     {
         return $this->mediaDescription;
     }
@@ -169,12 +169,12 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getEnclosureMime()
+    public function getEnclosureMime(): ?string
     {
         return $this->enclosureMime;
     }
 
-    public function getFeedId()
+    public function getFeedId(): string
     {
         return $this->feedId;
     }
@@ -182,7 +182,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getFingerprint()
+    public function getFingerprint(): ?string
     {
         return $this->fingerprint;
     }
@@ -197,12 +197,12 @@ class Item extends Entity implements IAPI, \JsonSerializable
         return $this->guidHash;
     }
 
-    public function getId()
+    public function getId(): string
     {
         return $this->id;
     }
 
-    public function getIntro()
+    public function getIntro(): string
     {
         return strip_tags($this->getBody());
     }
@@ -210,7 +210,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return string|null
      */
-    public function getLastModified()
+    public function getLastModified(): ?string
     {
         return $this->lastModified;
     }
@@ -218,7 +218,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return int|null
      */
-    public function getPubDate()
+    public function getPubDate(): ?int
     {
         return $this->pubDate;
     }
@@ -231,7 +231,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getSearchIndex()
+    public function getSearchIndex(): ?string
     {
         return $this->searchIndex;
     }
@@ -239,7 +239,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getTitle()
+    public function getTitle(): ?string
     {
         return $this->title;
     }
@@ -247,7 +247,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return int|null
      */
-    public function getUpdatedDate()
+    public function getUpdatedDate(): ?int
     {
         return $this->updatedDate;
     }
@@ -255,17 +255,17 @@ class Item extends Entity implements IAPI, \JsonSerializable
     /**
      * @return null|string
      */
-    public function getUrl()
+    public function getUrl(): ?string
     {
         return $this->url;
     }
 
-    public function isStarred()
+    public function isStarred(): bool
     {
         return $this->starred;
     }
 
-    public function isUnread()
+    public function isUnread(): bool
     {
         return $this->unread;
     }
@@ -299,7 +299,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         ];
     }
 
-    public function setAuthor(string $author = null)
+    public function setAuthor(string $author = null): void
     {
         $author = strip_tags($author);
 
@@ -309,7 +309,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setBody(string $body = null)
+    public function setBody(string $body = null): void
     {
         // FIXME: this should not happen if the target="_blank" is already
         // on the link
@@ -321,7 +321,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setContentHash(string $contentHash = null)
+    public function setContentHash(string $contentHash = null): void
     {
         if ($this->contentHash !== $contentHash) {
             $this->contentHash = $contentHash;
@@ -329,7 +329,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setEnclosureLink(string $enclosureLink = null)
+    public function setEnclosureLink(string $enclosureLink = null): void
     {
         if ($this->enclosureLink !== $enclosureLink) {
             $this->enclosureLink = $enclosureLink;
@@ -337,7 +337,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setEnclosureMime(string $enclosureMime = null)
+    public function setEnclosureMime(string $enclosureMime = null): void
     {
         if ($this->enclosureMime !== $enclosureMime) {
             $this->enclosureMime = $enclosureMime;
@@ -345,7 +345,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setMediaThumbnail(string $mediaThumbnail = null)
+    public function setMediaThumbnail(string $mediaThumbnail = null): void
     {
         if ($this->mediaThumbnail !== $mediaThumbnail) {
             $this->mediaThumbnail = $mediaThumbnail;
@@ -353,7 +353,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setMediaDescription(string $mediaDescription = null)
+    public function setMediaDescription(string $mediaDescription = null): void
     {
         if ($this->mediaDescription !== $mediaDescription) {
             $this->mediaDescription = $mediaDescription;
@@ -361,7 +361,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setFeedId(int $feedId)
+    public function setFeedId(int $feedId): void
     {
         if ($this->feedId !== $feedId) {
             $this->feedId = $feedId;
@@ -369,7 +369,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setFingerprint(string $fingerprint = null)
+    public function setFingerprint(string $fingerprint = null): void
     {
         if ($this->fingerprint !== $fingerprint) {
             $this->fingerprint = $fingerprint;
@@ -377,7 +377,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setGuid(string $guid)
+    public function setGuid(string $guid): void
     {
         if ($this->guid !== $guid) {
             $this->guid = $guid;
@@ -385,7 +385,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setGuidHash(string $guidHash)
+    public function setGuidHash(string $guidHash): void
     {
         if ($this->guidHash !== $guidHash) {
             $this->guidHash = $guidHash;
@@ -393,7 +393,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setId(int $id)
+    public function setId(int $id): void
     {
         if ($this->id !== $id) {
             $this->id = $id;
@@ -401,7 +401,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setLastModified(string $lastModified = null)
+    public function setLastModified(string $lastModified = null): void
     {
         if ($this->lastModified !== $lastModified) {
             $this->lastModified = $lastModified;
@@ -409,7 +409,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setPubDate(int $pubDate = null)
+    public function setPubDate(int $pubDate = null): void
     {
         if ($this->pubDate !== $pubDate) {
             $this->pubDate = $pubDate;
@@ -417,7 +417,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setRtl(bool $rtl)
+    public function setRtl(bool $rtl): void
     {
         if ($this->rtl !== $rtl) {
             $this->rtl = $rtl;
@@ -425,7 +425,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setSearchIndex(string $searchIndex = null)
+    public function setSearchIndex(string $searchIndex = null): void
     {
         if ($this->searchIndex !== $searchIndex) {
             $this->searchIndex = $searchIndex;
@@ -433,7 +433,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setStarred(bool $starred)
+    public function setStarred(bool $starred): void
     {
         if ($this->starred !== $starred) {
             $this->starred = $starred;
@@ -441,7 +441,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setTitle(string $title = null)
+    public function setTitle(string $title = null): void
     {
         $title = strip_tags($title);
 
@@ -451,7 +451,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setUnread(bool $unread)
+    public function setUnread(bool $unread): void
     {
         if ($this->unread !== $unread) {
             $this->unread = $unread;
@@ -459,7 +459,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setUpdatedDate(int $updatedDate = null)
+    public function setUpdatedDate(int $updatedDate = null): void
     {
         if ($this->updatedDate !== $updatedDate) {
             $this->updatedDate = $updatedDate;
@@ -467,7 +467,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
         }
     }
 
-    public function setUrl(string $url = null)
+    public function setUrl(string $url = null): void
     {
         $url = trim($url);
         if ((strpos($url, 'http') === 0 || strpos($url, 'magnet') === 0)
@@ -549,7 +549,7 @@ class Item extends Entity implements IAPI, \JsonSerializable
      *
      * @return boolean
      */
-    public function isSupportedMime($mime)
+    public function isSupportedMime(string $mime): bool
     {
         return (
             stripos($mime, 'audio/') !== false ||
diff --git a/lib/Db/ItemMapperV2.php b/lib/Db/ItemMapperV2.php
index ba840fda7..edb8ba55f 100644
--- a/lib/Db/ItemMapperV2.php
+++ b/lib/Db/ItemMapperV2.php
@@ -43,10 +43,11 @@ class ItemMapperV2 extends NewsMapperV2
      * Find all feeds for a user.
      *
      * @param string $userId The user identifier
+     * @param array  $params Filter parameters
      *
      * @return Entity[]
      */
-    public function findAllFromUser($userId): array
+    public function findAllFromUser(string $userId, array $params = []): array
     {
         $builder = $this->db->getQueryBuilder();
         $builder->select('items.*')
@@ -56,6 +57,11 @@ class ItemMapperV2 extends NewsMapperV2
                 ->andWhere('deleted_at = 0')
                 ->setParameter(':user_id', $userId, IQueryBuilder::PARAM_STR);
 
+        foreach ($params as $key => $value) {
+            $builder->andWhere("${key} = :${key}")
+                    ->setParameter(":${key}", $value);
+        }
+
         return $this->findEntities($builder);
     }
 
@@ -110,7 +116,7 @@ class ItemMapperV2 extends NewsMapperV2
      *
      * @param int $threshold Deletion threshold
      */
-    public function deleteOverThreshold($threshold)
+    public function deleteOverThreshold(int $threshold)
     {
         $builder = $this->db->getQueryBuilder();
 
diff --git a/lib/Db/NewsMapperV2.php b/lib/Db/NewsMapperV2.php
index be5695598..2896d9052 100644
--- a/lib/Db/NewsMapperV2.php
+++ b/lib/Db/NewsMapperV2.php
@@ -88,10 +88,11 @@ abstract class NewsMapperV2 extends QBMapper
      * Find all items for a user.
      *
      * @param string $userId ID of the user
+     * @param array  $params Filter parameters
      *
      * @return Entity[]
      */
-    abstract public function findAllFromUser(string $userId): array;
+    abstract public function findAllFromUser(string $userId, array $params = []): array;
 
     /**
      * Find item for a user.
diff --git a/lib/Explore/RecommendedSites.php b/lib/Explore/RecommendedSites.php
index 38fa510da..59ca3f337 100644
--- a/lib/Explore/RecommendedSites.php
+++ b/lib/Explore/RecommendedSites.php
@@ -35,7 +35,7 @@ class RecommendedSites
      *
      * @throws RecommendedSiteNotFoundException
      */
-    public function forLanguage(string $languageCode)
+    public function forLanguage(string $languageCode): array
     {
         $file = $this->directory . '/feeds.' . $languageCode . '.json';
 
diff --git a/lib/Fetcher/Fetcher.php b/lib/Fetcher/Fetcher.php
index 955875084..883fa49e4 100644
--- a/lib/Fetcher/Fetcher.php
+++ b/lib/Fetcher/Fetcher.php
@@ -35,7 +35,7 @@ class Fetcher
      *
      * @param IFeedFetcher $fetcher the fetcher
      */
-    public function registerFetcher(IFeedFetcher $fetcher)
+    public function registerFetcher(IFeedFetcher $fetcher): void
     {
         $this->fetchers[] = $fetcher;
     }
@@ -62,7 +62,7 @@ class Fetcher
         bool $fullTextEnabled = false,
         ?string $user = null,
         ?string $password = null
-    ) {
+    ): array {
         foreach ($this->fetchers as $fetcher) {
             if (!$fetcher->canHandle($url)) {
                 continue;
diff --git a/lib/Fetcher/FetcherException.php b/lib/Fetcher/FetcherException.php
index 82772eaf5..263b54239 100644
--- a/lib/Fetcher/FetcherException.php
+++ b/lib/Fetcher/FetcherException.php
@@ -21,7 +21,7 @@ class FetcherException extends \Exception
      *
      * @param string $msg the error message
      */
-    public function __construct($msg)
+    public function __construct(string $msg)
     {
         parent::__construct($msg);
     }
diff --git a/lib/Fetcher/YoutubeFetcher.php b/lib/Fetcher/YoutubeFetcher.php
index 67a4d5afa..7c197a1b1 100644
--- a/lib/Fetcher/YoutubeFetcher.php
+++ b/lib/Fetcher/YoutubeFetcher.php
@@ -29,7 +29,7 @@ class YoutubeFetcher implements IFeedFetcher
      *
      * @return string
      */
-    private function buildUrl(string $url)
+    private function buildUrl(string $url): string
     {
         $baseRegex = '%(?:https?://|//)?(?:www.)?youtube.com';
         $playRegex = $baseRegex . '.*?list=([^&]*)%';
diff --git a/lib/Http/TextDownloadResponse.php b/lib/Http/TextDownloadResponse.php
deleted file mode 100644
index 6a0f72e0c..000000000
--- a/lib/Http/TextDownloadResponse.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-/**
- * Nextcloud - News
- *
- * This file is licensed under the Affero General Public License version 3 or
- * later. See the COPYING file.
- *
- * @author    Alessandro Cosentino <cosenal@gmail.com>
- * @author    Bernhard Posselt <dev@bernhard-posselt.com>
- * @copyright 2012 Alessandro Cosentino
- * @copyright 2012-2014 Bernhard Posselt
- */
-
-namespace OCA\News\Http;
-
-use \OCP\AppFramework\Http\DownloadResponse;
-
-/**
- * Prompts the user to download the a text file
- */
-class TextDownloadResponse extends DownloadResponse
-{
-
-    private $content;
-
-    /**
-     * Creates a response that prompts the user to download a file which
-     * contains the passed string
-     *
-     * @param string $content     the content that should be written into the file
-     * @param string $filename    the name that the downloaded file should have
-     * @param string $contentType the mimetype that the downloaded file should
-     *                            have
-     */
-    public function __construct($content, $filename, $contentType)
-    {
-        parent::__construct($filename, $contentType);
-        $this->content = $content;
-    }
-
-
-    /**
-     * Simply sets the headers and returns the file contents
-     *
-     * @return string the file contents
-     */
-    public function render()
-    {
-        return $this->content;
-    }
-}
diff --git a/lib/Http/TextResponse.php b/lib/Http/TextResponse.php
deleted file mode 100644
index fd97feae2..000000000
--- a/lib/Http/TextResponse.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-/**
- * Nextcloud - News
- *
- * This file is licensed under the Affero General Public License version 3 or
- * later. See the COPYING file.
- *
- * @author    Alessandro Cosentino <cosenal@gmail.com>
- * @author    Bernhard Posselt <dev@bernhard-posselt.com>
- * @copyright 2012 Alessandro Cosentino
- * @copyright 2012-2014 Bernhard Posselt
- */
-
-namespace OCA\News\Http;
-
-use \OCP\AppFramework\Http\Response;
-
-/**
- * Just outputs text to the browser
- */
-class TextResponse extends Response
-{
-
-    private $content;
-
-    /**
-     * Creates a response that just outputs text
-     *
-     * @param string $content     the content that should be written into the file
-     * @param string $contentType the mimetype. text/ is added automatically so
-     *                            only plain or html can be added to get text/plain or text/html
-     */
-    public function __construct($content, $contentType = 'plain')
-    {
-        $this->content = $content;
-        $this->addHeader('Content-type', 'text/' . $contentType);
-    }
-
-
-    /**
-     * Simply sets the headers and returns the file contents
-     *
-     * @return string the file contents
-     */
-    public function render()
-    {
-        return $this->content;
-    }
-}
diff --git a/lib/Service/Exceptions/ServiceConflictException.php b/lib/Service/Exceptions/ServiceConflictException.php
index 4a1a80801..dd6ba03c9 100644
--- a/lib/Service/Exceptions/ServiceConflictException.php
+++ b/lib/Service/Exceptions/ServiceConflictException.php
@@ -21,7 +21,7 @@ class ServiceConflictException extends ServiceException
      *
      * @param string $msg the error message
      */
-    public function __construct($msg)
+    public function __construct(string $msg)
     {
         parent::__construct($msg);
     }
diff --git a/lib/Service/Exceptions/ServiceException.php b/lib/Service/Exceptions/ServiceException.php
index 7ee53bef9..c5ddddbd9 100644
--- a/lib/Service/Exceptions/ServiceException.php
+++ b/lib/Service/Exceptions/ServiceException.php
@@ -21,7 +21,7 @@ class ServiceException extends \Exception
      *
      * @param string $msg the error message
      */
-    public function __construct($msg)
+    public function __construct(string $msg)
     {
         parent::__construct($msg);
     }
diff --git a/lib/Service/Exceptions/ServiceNotFoundException.php b/lib/Service/Exceptions/ServiceNotFoundException.php
index 6a9bae192..6c68ea6b2 100644
--- a/lib/Service/Exceptions/ServiceNotFoundException.php
+++ b/lib/Service/Exceptions/ServiceNotFoundException.php
@@ -21,7 +21,7 @@ class ServiceNotFoundException extends ServiceException
      *
      * @param string $msg the error message
      */
-    public function __construct($msg)
+    public function __construct(string $msg)
     {
         parent::__construct($msg);
     }
diff --git a/lib/Service/Exceptions/ServiceValidationException.php b/lib/Service/Exceptions/ServiceValidationException.php
index 8d1bf09c8..8e9dc9fee 100644
--- a/lib/Service/Exceptions/ServiceValidationException.php
+++ b/lib/Service/Exceptions/ServiceValidationException.php
@@ -21,7 +21,7 @@ class ServiceValidationException extends ServiceException
      *
      * @param string $msg the error message
      */
-    public function __construct($msg)
+    public function __construct(string $msg)
     {
         parent::__construct($msg);
     }
diff --git a/lib/Service/FeedService.php b/lib/Service/FeedService.php
index 55807b45a..ab9c18219 100644
--- a/lib/Service/FeedService.php
+++ b/lib/Service/FeedService.php
@@ -83,7 +83,7 @@ class FeedService extends Service
      *
      * @return Feed[]
      */
-    public function findAllForUser($userId): array
+    public function findAllForUser($userId, array $params = []): array
     {
         return $this->feedMapper->findAllFromUser($userId);
     }
diff --git a/lib/Service/FeedServiceV2.php b/lib/Service/FeedServiceV2.php
index 58217a1ce..55137c357 100644
--- a/lib/Service/FeedServiceV2.php
+++ b/lib/Service/FeedServiceV2.php
@@ -89,7 +89,7 @@ class FeedServiceV2 extends Service
      *
      * @return Feed[]
      */
-    public function findAllForUser(string $userId): array
+    public function findAllForUser(string $userId, array $params = []): array
     {
         return $this->mapper->findAllFromUser($userId);
     }
diff --git a/lib/Service/FolderService.php b/lib/Service/FolderService.php
index ed95f81f4..cd8b4b852 100644
--- a/lib/Service/FolderService.php
+++ b/lib/Service/FolderService.php
@@ -65,7 +65,7 @@ class FolderService extends Service
      *
      * @return Folder[]
      */
-    public function findAllForUser(string $userId): array
+    public function findAllForUser(string $userId, array $params = []): array
     {
         return $this->folderMapper->findAllFromUser($userId);
     }
diff --git a/lib/Service/FolderServiceV2.php b/lib/Service/FolderServiceV2.php
index 0e15ddde5..b1290eca2 100644
--- a/lib/Service/FolderServiceV2.php
+++ b/lib/Service/FolderServiceV2.php
@@ -47,7 +47,7 @@ class FolderServiceV2 extends Service
      *
      * @return Folder[]
      */
-    public function findAllForUser(string $userId): array
+    public function findAllForUser(string $userId, array $params = []): array
     {
         return $this->mapper->findAllFromUser($userId);
     }
diff --git a/lib/Service/ItemService.php b/lib/Service/ItemService.php
index 3a0270658..5f85e0b84 100644
--- a/lib/Service/ItemService.php
+++ b/lib/Service/ItemService.php
@@ -150,7 +150,7 @@ class ItemService extends Service
         }
     }
 
-    public function findAllForUser(string $userId): array
+    public function findAllForUser(string $userId, array $params = []): array
     {
         return $this->itemMapper->findAllFromUser($userId);
     }
diff --git a/lib/Service/ItemServiceV2.php b/lib/Service/ItemServiceV2.php
index 879b2908f..1e4fe1eac 100644
--- a/lib/Service/ItemServiceV2.php
+++ b/lib/Service/ItemServiceV2.php
@@ -51,13 +51,15 @@ class ItemServiceV2 extends Service
     /**
      * Finds all items of a user
      *
-     * @param string $userId the name of the user
+     * @param string $userId The ID/name of the user
+     * @param array $params Filter parameters
+     *
      *
      * @return Item[]
      */
-    public function findAllForUser($userId): array
+    public function findAllForUser(string $userId, array $params = []): array
     {
-        return $this->mapper->findAllFromUser($userId);
+        return $this->mapper->findAllFromUser($userId, $params);
     }
 
     /**
@@ -86,7 +88,7 @@ class ItemServiceV2 extends Service
         return $this->mapper->findAllForFeed($feedId);
     }
 
-    public function purgeOverThreshold($threshold = null)
+    public function purgeOverThreshold(int $threshold = null)
     {
 
         $threshold = (int) $threshold ?? $this->config->getAppValue(
diff --git a/lib/Service/OpmlService.php b/lib/Service/OpmlService.php
new file mode 100644
index 000000000..ea570cf68
--- /dev/null
+++ b/lib/Service/OpmlService.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Nextcloud - News
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author    Alessandro Cosentino <cosenal@gmail.com>
+ * @author    Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright 2012 Alessandro Cosentino
+ * @copyright 2012-2014 Bernhard Posselt
+ */
+
+
+namespace OCA\News\Service;
+
+use OCA\News\Utility\OPMLExporter;
+
+class OpmlService
+{
+
+    /**
+     * @var FolderService
+     */
+    private $folderService;
+
+    /**
+     * @var FeedService
+     */
+    private $feedService;
+
+    /**
+     * @var ItemService
+     */
+    private $itemService;
+
+    /**
+     * @var OPMLExporter
+     */
+    private $exporter;
+
+    public function __construct(
+        FolderServiceV2 $folderService,
+        FeedServiceV2 $feedService,
+        ItemServiceV2 $itemService,
+        OPMLExporter $exporter
+    ) {
+        $this->folderService = $folderService;
+        $this->feedService = $feedService;
+        $this->itemService = $itemService;
+        $this->exporter = $exporter;
+    }
+
+    /**
+     * Export all feeds for a user.
+     *
+     * @param string $userId User ID
+     *
+     * @return string Exported OPML data
+     */
+    public function export(string $userId): string
+    {
+        $feeds   = $this->feedService->findAllForUser($userId);
+        $folders = $this->folderService->findAllForUser($userId);
+
+        return $this->exporter->build($folders, $feeds)
+                              ->saveXML();
+    }
+}
diff --git a/lib/Service/Service.php b/lib/Service/Service.php
index 33397bc0f..04965af4b 100644
--- a/lib/Service/Service.php
+++ b/lib/Service/Service.php
@@ -52,11 +52,12 @@ abstract class Service
     /**
      * Finds all items of a user
      *
-     * @param string $userId the name of the user
+     * @param string $userId The ID/name of the user
+     * @param array  $params Filter parameters
      *
      * @return Entity[]
      */
-    abstract public function findAllForUser(string $userId): array;
+    abstract public function findAllForUser(string $userId, array $params = []): array;
 
     /**
      * Finds all items
@@ -89,7 +90,7 @@ abstract class Service
      * @param int    $id     the id of the entity
      * @param string $userId the name of the user for security reasons
      *
-     * @return \OCP\AppFramework\Db\Entity the entity
+     * @return Entity the entity
      * @throws ServiceNotFoundException if the entity does not exist, or there
      * are more than one of it
      */
diff --git a/lib/Service/UpdaterService.php b/lib/Service/UpdaterService.php
index dadd667f5..c18eed8d7 100644
--- a/lib/Service/UpdaterService.php
+++ b/lib/Service/UpdaterService.php
@@ -14,14 +14,6 @@
 
 namespace OCA\News\Service;
 
-use OCA\News\Db\ItemMapperV2;
-use OCA\News\Service\FeedServiceV2;
-use OCA\News\Service\FolderServiceV2;
-use OCA\News\Service\ItemServiceV2;
-use \OCA\News\Service\LegacyFolderService;
-use \OCA\News\Service\FeedService;
-use \OCA\News\Service\ItemService;
-
 class UpdaterService
 {
 
diff --git a/lib/Settings/Section.php b/lib/Settings/AdminSection.php
similarity index 93%
rename from lib/Settings/Section.php
rename to lib/Settings/AdminSection.php
index 245dec0e7..f92c9a8a4 100644
--- a/lib/Settings/Section.php
+++ b/lib/Settings/AdminSection.php
@@ -6,7 +6,7 @@ use OCP\IL10N;
 use OCP\IURLGenerator;
 use OCP\Settings\IIconSection;
 
-class Section implements IIconSection
+class AdminSection implements IIconSection
 {
     private $l;
     private $url;
diff --git a/lib/Utility/OPMLExporter.php b/lib/Utility/OPMLExporter.php
index 8c21fa204..880222da0 100644
--- a/lib/Utility/OPMLExporter.php
+++ b/lib/Utility/OPMLExporter.php
@@ -16,6 +16,7 @@ namespace OCA\News\Utility;
 use \DOMDocument;
 use \DOMElement;
 use OCA\News\Db\Feed;
+use OCA\News\Db\Folder;
 
 /**
  * Exports the OPML
@@ -26,8 +27,8 @@ class OPMLExporter
     /**
      * Generates the OPML for the active user
      *
-     * @param  \OCA\News\Db\Folder[] $folders
-     * @param  \OCA\News\Db\Feed[]   $feeds
+     * @param Folder[] $folders
+     * @param Feed[]    $feeds
      * @return DOMDocument the document
      */
     public function build(array $folders, array $feeds)
diff --git a/tests/Unit/Controller/ExportControllerTest.php b/tests/Unit/Controller/ExportControllerTest.php
index 94ffa1ed1..563bd987c 100644
--- a/tests/Unit/Controller/ExportControllerTest.php
+++ b/tests/Unit/Controller/ExportControllerTest.php
@@ -14,14 +14,15 @@
 namespace OCA\News\Tests\Unit\Controller;
 
 use OCA\News\Controller\ExportController;
-use OCA\News\Service\FeedService;
-use OCA\News\Service\FolderService;
-use OCA\News\Service\ItemService;
+use OCA\News\Service\FeedServiceV2;
+use OCA\News\Service\FolderServiceV2;
 
-use \OCA\News\Http\TextDownloadResponse;
+use OCA\News\Service\ItemServiceV2;
+use OCA\News\Service\OpmlService;
 use \OCA\News\Utility\OPMLExporter;
 use \OCA\News\Db\Item;
 use \OCA\News\Db\Feed;
+use OCP\AppFramework\Http\DataDownloadResponse;
 use OCP\IRequest;
 
 use PHPUnit\Framework\TestCase;
@@ -29,39 +30,55 @@ use PHPUnit\Framework\TestCase;
 class ExportControllerTest extends TestCase
 {
 
-    private $appName;
-    private $request;
     private $controller;
     private $user;
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|FeedServiceV2
+     */
     private $feedService;
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|FolderServiceV2
+     */
     private $folderService;
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|ItemServiceV2
+     */
     private $itemService;
-    private $opmlExporter;
+    /**
+     * @var \PHPUnit\Framework\MockObject\MockObject|OpmlService
+     */
+    private $opmlService;
 
     /**
      * Gets run before each test
      */
     public function setUp(): void
     {
-        $this->appName = 'news';
+        $appName = 'news';
         $this->user = 'john';
-        $this->itemService = $this->getMockBuilder(ItemService::class)
+        $this->itemService = $this->getMockBuilder(ItemServiceV2::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->feedService = $this->getMockBuilder(FeedService::class)
+        $this->feedService = $this->getMockBuilder(FeedServiceV2::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->folderService = $this->getMockBuilder(FolderService::class)
+        $this->folderService = $this->getMockBuilder(FolderServiceV2::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->request = $this->getMockBuilder(IRequest::class)
+        $this->opmlService = $this->getMockBuilder(OpmlService::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $request = $this->getMockBuilder(IRequest::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->opmlExporter = new OPMLExporter();
         $this->controller = new ExportController(
-            $this->appName, $this->request,
-            $this->folderService, $this->feedService,
-            $this->itemService, $this->opmlExporter, $this->user
+            $appName,
+            $request,
+            $this->folderService,
+            $this->feedService,
+            $this->itemService,
+            $this->opmlService,
+            $this->user
         );
     }
 
@@ -77,17 +94,13 @@ class ExportControllerTest extends TestCase
         "  <body/>\n" .
         "</opml>\n";
 
-        $this->feedService->expects($this->once())
-            ->method('findAll')
-            ->with($this->equalTo($this->user))
-            ->will($this->returnValue([]));
-        $this->folderService->expects($this->once())
-            ->method('findAll')
-            ->with($this->equalTo($this->user))
-            ->will($this->returnValue([]));
+        $this->opmlService->expects($this->once())
+            ->method('export')
+            ->with($this->user)
+            ->will($this->returnValue($opml));
 
         $return = $this->controller->opml();
-        $this->assertTrue($return instanceof TextDownloadResponse);
+        $this->assertTrue($return instanceof DataDownloadResponse);
         $this->assertEquals($opml, $return->render());
     }
 
@@ -112,12 +125,12 @@ class ExportControllerTest extends TestCase
         $articles = [$item1, $item2];
 
         $this->feedService->expects($this->once())
-            ->method('findAll')
-            ->with($this->equalTo($this->user))
+            ->method('findAllForUser')
+            ->with($this->user)
             ->will($this->returnValue($feeds));
         $this->itemService->expects($this->once())
-            ->method('getUnreadOrStarred')
-            ->with($this->equalTo($this->user))
+            ->method('findAllForUser')
+            ->with($this->user, ['unread' => true, 'starred' => true])
             ->will($this->returnValue($articles));
 
 
diff --git a/tests/Unit/Controller/FolderApiControllerTest.php b/tests/Unit/Controller/FolderApiControllerTest.php
index de62b887a..3c5650e5c 100644
--- a/tests/Unit/Controller/FolderApiControllerTest.php
+++ b/tests/Unit/Controller/FolderApiControllerTest.php
@@ -81,7 +81,7 @@ class FolderApiControllerTest extends TestCase
         $folders = [new Folder()];
 
         $this->folderService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllForUser')
             ->with($this->equalTo($this->user->getUID()))
             ->will($this->returnValue($folders));
 
diff --git a/tests/Unit/Controller/FolderControllerTest.php b/tests/Unit/Controller/FolderControllerTest.php
index ea3454656..94c7b1c53 100644
--- a/tests/Unit/Controller/FolderControllerTest.php
+++ b/tests/Unit/Controller/FolderControllerTest.php
@@ -72,7 +72,7 @@ class FolderControllerTest extends TestCase
     {
         $return = [new Folder(), new Folder()];
         $this->folderService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllForUser')
             ->will($this->returnValue($return));
 
         $response = $this->controller->index();
@@ -303,7 +303,7 @@ class FolderControllerTest extends TestCase
                 $this->equalTo($this->user)
             );
         $this->feedService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllForUser')
             ->with($this->equalTo($this->user))
             ->will($this->returnValue([$feed]));
 
diff --git a/tests/Unit/Controller/ItemApiControllerTest.php b/tests/Unit/Controller/ItemApiControllerTest.php
index 1360ad872..d2653b92a 100644
--- a/tests/Unit/Controller/ItemApiControllerTest.php
+++ b/tests/Unit/Controller/ItemApiControllerTest.php
@@ -80,7 +80,7 @@ class ItemApiControllerTest extends TestCase
         $item->setFeedId(123);
 
         $this->itemService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllItems')
             ->with(
                 $this->equalTo(2),
                 $this->equalTo(1),
@@ -111,7 +111,7 @@ class ItemApiControllerTest extends TestCase
         $item->setFeedId(123);
 
         $this->itemService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllItems')
             ->with(
                 $this->equalTo(2),
                 $this->equalTo(1),
diff --git a/tests/Unit/Controller/ItemControllerTest.php b/tests/Unit/Controller/ItemControllerTest.php
index a0780cecb..c69191423 100644
--- a/tests/Unit/Controller/ItemControllerTest.php
+++ b/tests/Unit/Controller/ItemControllerTest.php
@@ -181,7 +181,7 @@ class ItemControllerTest extends TestCase
                 $this->equalTo($this->user)
             );
         $this->feedService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllForUser')
             ->with($this->equalTo($this->user))
             ->will($this->returnValue([$feed]));
 
@@ -240,7 +240,7 @@ class ItemControllerTest extends TestCase
         $this->itemsApiExpects(2, FeedType::FEED, '0');
 
         $this->feedService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllForUser')
             ->with($this->equalTo($this->user))
             ->will($this->returnValue($feeds));
 
@@ -255,7 +255,7 @@ class ItemControllerTest extends TestCase
             ->will($this->returnValue(3111));
 
         $this->itemService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllItems')
             ->with(
                 $this->equalTo(2),
                 $this->equalTo(FeedType::FEED),
@@ -286,7 +286,7 @@ class ItemControllerTest extends TestCase
         $this->itemsApiExpects(2, FeedType::FEED, '0');
 
         $this->feedService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllForUser')
             ->with($this->equalTo($this->user))
             ->will($this->returnValue($feeds));
 
@@ -301,7 +301,7 @@ class ItemControllerTest extends TestCase
             ->will($this->returnValue(3111));
 
         $this->itemService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllItems')
             ->with(
                 $this->equalTo(2),
                 $this->equalTo(FeedType::FEED),
@@ -329,7 +329,7 @@ class ItemControllerTest extends TestCase
         $this->itemsApiExpects(2, FeedType::FEED);
 
         $this->itemService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllItems')
             ->with(
                 $this->equalTo(2),
                 $this->equalTo(FeedType::FEED),
@@ -342,7 +342,7 @@ class ItemControllerTest extends TestCase
             ->will($this->returnValue($result['items']));
 
         $this->feedService->expects($this->never())
-            ->method('findAll');
+            ->method('findAllForUser');
 
         $response = $this->controller->index(FeedType::FEED, 2, 3, 10);
         $this->assertEquals($result, $response);
@@ -383,7 +383,7 @@ class ItemControllerTest extends TestCase
             ->will($this->returnValue('1'));
 
         $this->feedService->expects($this->once())
-            ->method('findAll')
+            ->method('findAllForUser')
             ->with($this->equalTo($this->user))
             ->will($this->returnValue($feeds));
 
diff --git a/tests/Unit/Controller/JSONHttpErrorTest.php b/tests/Unit/Controller/JSONHttpErrorTest.php
index 3b48bc36e..8bfb11f3e 100644
--- a/tests/Unit/Controller/JSONHttpErrorTest.php
+++ b/tests/Unit/Controller/JSONHttpErrorTest.php
@@ -14,14 +14,8 @@
 namespace OCA\News\Tests\Unit\Controller;
 
 use OCA\News\Controller\JSONHttpErrorTrait;
-
 use PHPUnit\Framework\TestCase;
 
-class Test
-{
-    use JSONHttpErrorTrait;
-}
-
 class JSONHttpErrorTest extends TestCase
 {
 
@@ -29,7 +23,7 @@ class JSONHttpErrorTest extends TestCase
     public function testError()
     {
         $ex = new \Exception('hi');
-        $test = new Test();
+        $test = new DummyTraitingClass();
         $result = $test->error($ex, 3);
 
         $this->assertEquals(['message' => 'hi'], $result->getData());
@@ -37,4 +31,10 @@ class JSONHttpErrorTest extends TestCase
     }
 
 
+}
+
+
+class DummyTraitingClass
+{
+    use JSONHttpErrorTrait;
 }
\ No newline at end of file
diff --git a/tests/Unit/Controller/PageControllerTest.php b/tests/Unit/Controller/PageControllerTest.php
index 69fed0d77..fe263f242 100644
--- a/tests/Unit/Controller/PageControllerTest.php
+++ b/tests/Unit/Controller/PageControllerTest.php
@@ -255,7 +255,7 @@ class PageControllerTest extends TestCase
 
     public function testExplore()
     {
-        $in = 'test';
+        $in = ['test'];
         $this->settings->expects($this->at(0))
             ->method('setUserValue')
             ->with('becka', 'news', 'lastViewedFeedId', 0);
diff --git a/tests/Unit/Http/TextDownloadResponseTest.php b/tests/Unit/Http/TextDownloadResponseTest.php
deleted file mode 100644
index be5f53ec1..000000000
--- a/tests/Unit/Http/TextDownloadResponseTest.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-/**
- * Nextcloud - News
- *
- * This file is licensed under the Affero General Public License version 3 or
- * later. See the COPYING file.
- *
- * @author    Alessandro Cosentino <cosenal@gmail.com>
- * @author    Bernhard Posselt <dev@bernhard-posselt.com>
- * @copyright 2012 Alessandro Cosentino
- * @copyright 2012-2014 Bernhard Posselt
- */
-
-
-namespace OCA\News\Tests\Unit\Http;
-
-
-use OCA\News\Http\TextDownloadResponse;
-use PHPUnit\Framework\TestCase;
-
-class TextDownloadResponseTest extends TestCase
-{
-
-
-    protected function setUp(): void
-    {
-        $this->response = new TextDownloadResponse(
-            'sometext', 'file', 'content'
-        );
-    }
-
-
-    public function testRender()
-    {
-        $this->assertEquals('sometext', $this->response->render());
-    }
-
-}
\ No newline at end of file
diff --git a/tests/Unit/Http/TextResponseTest.php b/tests/Unit/Http/TextResponseTest.php
deleted file mode 100644
index eaad769b5..000000000
--- a/tests/Unit/Http/TextResponseTest.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-/**
- * Nextcloud - News
- *
- * This file is licensed under the Affero General Public License version 3 or
- * later. See the COPYING file.
- *
- * @author    Alessandro Cosentino <cosenal@gmail.com>
- * @author    Bernhard Posselt <dev@bernhard-posselt.com>
- * @copyright 2012 Alessandro Cosentino
- * @copyright 2012-2014 Bernhard Posselt
- */
-
-
-namespace OCA\News\Tests\Unit\Http;
-
-use PHPUnit\Framework\TestCase;
-use OCA\News\Http\TextResponse;
-
-class TextResponseTest extends TestCase
-{
-
-
-    protected function setUp(): void
-    {
-        $this->response = new TextResponse('sometext');
-    }
-
-
-    public function testRender()
-    {
-        $this->assertEquals('sometext', $this->response->render());
-    }
-
-    public function testContentTypeDefaultsToText()
-    {
-        $headers = $this->response->getHeaders();
-
-        $this->assertEquals('text/plain', $headers['Content-type']);
-    }
-
-
-    public function testContentTypeIsSetableViaConstructor()
-    {
-        $response = new TextResponse('sometext', 'html');
-        $headers = $response->getHeaders();
-
-        $this->assertEquals('text/html', $headers['Content-type']);
-    }
-
-}
\ No newline at end of file
diff --git a/tests/Unit/Service/ServiceTest.php b/tests/Unit/Service/ServiceTest.php
index e243efb3f..4b6c6b03d 100644
--- a/tests/Unit/Service/ServiceTest.php
+++ b/tests/Unit/Service/ServiceTest.php
@@ -32,7 +32,7 @@ class TestLegacyService extends Service
         parent::__construct($mapper, $logger);
     }
 
-    public function findAllForUser(string $userId): array
+    public function findAllForUser(string $userId, array $params = []): array
     {
         // TODO: Implement findAllForUser() method.
     }