diff --git a/aleksis/apps/resint/frontend/index.js b/aleksis/apps/resint/frontend/index.js
index ff8b4c56321a3362fc00224b01800f62466f9a1f..e415bfebf61e4d786b1649614587d399438e6647 100644
--- a/aleksis/apps/resint/frontend/index.js
+++ b/aleksis/apps/resint/frontend/index.js
@@ -1 +1,153 @@
-export default {};
+import { hasPersonValidator } from "aleksis.core/routeValidators";
+
+export default
+  {
+    meta: {
+      inMenu: true,
+      titleKey: "resint.menu_title",
+      icon: "mdi-open-in-app",
+      validators: [
+        hasPersonValidator
+      ]
+    },
+    children: [
+      {
+        path: "",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.posterIndex",
+        meta: {
+          inMenu: true,
+          titleKey: "resint.manage_posters.menu_title",
+          icon: "mdi-file-upload-outline",
+          permission: "resint.view_posters_rule",
+        },
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "upload/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.posterUpload",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: ":pk/edit/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.posterEdit",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: ":pk/delete/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.posterDelete",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: ":slug.pdf",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.posterShowCurrent",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "groups/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.posterGroupList",
+        meta: {
+          inMenu: true,
+          titleKey: "resint.poster_groups.menu_title",
+          icon: "mdi-folder-multiple-outline",
+          permission: "resint.view_postergroups_rule",
+        },
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "groups/create/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.createPosterGroup",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "groups/:pk/edit/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.editPosterGroup",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "groups/:pk/delete/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.deletePosterGroup",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "live/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.liveDocuments",
+        meta: {
+          inMenu: true,
+          titleKey: "resint.live_documents.menu_title",
+          icon: "mdi-update",
+          permission: "resint.view_livedocuments_rule",
+        },
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "live/:app/:model/create/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.createLiveDocument",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "live/:pk/edit/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.editLiveDocument",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "live_documents/:pk/delete/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.deleteLiveDocument",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "live_documents/:slug.pdf",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.showLiveDocument",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "api/live_documents/:slug.pdf",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "resint.apiShowLiveDocument",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+    ],
+  }
diff --git a/aleksis/apps/resint/frontend/messages/en.json b/aleksis/apps/resint/frontend/messages/en.json
index 0db3279e44b0dc4fb7e694b6cb10210a96ba6ba5..376a6a7ea193f002f41a927b604563e5cbdba081 100644
--- a/aleksis/apps/resint/frontend/messages/en.json
+++ b/aleksis/apps/resint/frontend/messages/en.json
@@ -1,3 +1,14 @@
 {
-
+  "resint": {
+    "menu_title": "Documents",
+    "manage_posters": {
+      "menu_title": "Manage posters"
+    },
+    "poster_groups": {
+      "menu_title": "Poster groups"
+    },
+    "live_documents": {
+      "menu_title": "Live documents"
+    }
+  }
 }
diff --git a/aleksis/apps/resint/menus.py b/aleksis/apps/resint/menus.py
deleted file mode 100644
index 2967079ee5c00b2955b5ce5c489fe38d7b06f5a0..0000000000000000000000000000000000000000
--- a/aleksis/apps/resint/menus.py
+++ /dev/null
@@ -1,87 +0,0 @@
-from typing import Any, Dict, List
-
-from django.apps import apps
-from django.urls import reverse
-from django.utils.translation import ugettext_lazy as _
-
-
-def _get_menu_entries() -> List[Dict[str, Any]]:
-    """Build menu entries for all poster groups.
-
-    This will include only poster groups where ``show_in_menu`` is enabled.
-    """
-    PosterGroup = apps.get_model("resint", "PosterGroup")
-    return [
-        {
-            "name": group.name,
-            "url": reverse("poster_show_current", args=[group.slug]),
-            "icon": "picture_as_pdf",
-            "validators": [
-                (
-                    "aleksis.apps.resint.rules.permission_validator",
-                    "resint.view_poster_pdf_menu",
-                    group,
-                ),
-            ],
-            "new_tab": True,
-        }
-        for group in PosterGroup.objects.all()
-    ]
-
-
-class MENUS:
-    def get(menu_name, default=None):
-        menus = {
-            "NAV_MENU_CORE": [
-                {
-                    "name": _("Documents"),
-                    "url": "#",
-                    "icon": "open_in_browser",
-                    "root": True,
-                    "validators": [
-                        (
-                            "aleksis.core.util.predicates.permission_validator",
-                            "resint.view_poster_menu",
-                        ),
-                    ],
-                    "submenu": [
-                        {
-                            "name": _("Manage posters"),
-                            "url": "poster_index",
-                            "icon": "file_upload",
-                            "validators": [
-                                (
-                                    "aleksis.core.util.predicates.permission_validator",
-                                    "resint.view_posters_rule",
-                                ),
-                            ],
-                        },
-                        {
-                            "name": _("Poster groups"),
-                            "url": "poster_group_list",
-                            "icon": "topic",
-                            "validators": [
-                                (
-                                    "aleksis.core.util.predicates.permission_validator",
-                                    "resint.view_postergroups_rule",
-                                ),
-                            ],
-                        },
-                        {
-                            "name": _("Live documents"),
-                            "url": "live_documents",
-                            "icon": "update",
-                            "validators": [
-                                (
-                                    "aleksis.core.util.predicates.permission_validator",
-                                    "resint.view_livedocuments_rule",
-                                ),
-                            ],
-                        },
-                    ],
-                }
-            ]
-            + _get_menu_entries(),
-        }
-
-        return menus.get(menu_name, default)
diff --git a/aleksis/apps/resint/models.py b/aleksis/apps/resint/models.py
index b7c9360c9949302b45790d11a7ed7b0435bcdc52..c42edc8538f32b9ee44e89862ec06e09bfa08fbc 100644
--- a/aleksis/apps/resint/models.py
+++ b/aleksis/apps/resint/models.py
@@ -43,16 +43,12 @@ class PosterGroupDynamicRoute(DynamicRoute):
 
       dynamic_route["display_account_menu"] = False
       dynamic_route["display_sidenav_menu"] = instance.show_in_menu
-      dynamic_route["sidenav_menu_root"] = True
       dynamic_route["menu_new_tab"] = True
 
       dynamic_route["menu_title"] = instance.name
       dynamic_route["menu_icon"] = "mdi-file-pdf-box"
 
-      dynamic_route["menu_permission"] = "resint.view_poster_pdf_menu"
-      dynamic_route["route_permission"] = "resint.view_poster_pdf_menu"
-
-      # TODO Handle case of posters that are supposed to be displayed even when user is not logged in
+      dynamic_route["route_permission"] = "" if instance.public else "resint.view_poster_pdf_menu"
 
       return dynamic_route
 
diff --git a/aleksis/apps/resint/rules.py b/aleksis/apps/resint/rules.py
index 1db1cfb625c8a2035a6d1d11063f78522d057685..57b9d6100cc420ee1f82700911cdeeb6f66fff05 100644
--- a/aleksis/apps/resint/rules.py
+++ b/aleksis/apps/resint/rules.py
@@ -102,7 +102,7 @@ view_poster_pdf_predicate = is_public_poster_group | (
 )
 add_perm("resint.view_poster_pdf", view_poster_pdf_predicate)
 
-# View menu entry for single posters
+# View poster PDF file in menu
 view_poster_pdf_menu_predicate = has_person & (
 	has_global_perm("resint.view_postergroup")
 	| has_global_perm("resint.view_poster")