diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 42d851f79bfa51e26f8cb5a97f101d02c207c47e..ddb4e4bce70f3876b67634c4f765a664ee8958ef 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -9,6 +9,11 @@ and this project adheres to `Semantic Versioning`_.
 Unreleased
 ----------
 
+Added
+~~~~~
+
+* Support for usage with new AlekSIS SPA.
+
 `1.0.2`_ - 2022-11-04
 ---------------------
 
diff --git a/aleksis/apps/stoelindeling/frontend/index.js b/aleksis/apps/stoelindeling/frontend/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..bb045a37152fa13fe8faaa142f6b6d79dbbd1a93
--- /dev/null
+++ b/aleksis/apps/stoelindeling/frontend/index.js
@@ -0,0 +1,68 @@
+export default
+  {
+    meta: {
+      inMenu: true,
+      titleKey: "stoelindeling.menu_title",
+      icon: "mdi-view-list-outline",
+    },
+    props: {
+      byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+    },
+    children: [
+      {
+        path: "seating_plans/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "stoelindeling.seatingPlans",
+        meta: {
+          inMenu: true,
+          titleKey: "stoelindeling.menu_title",
+          icon: "mdi-view-list-outline",
+          permission: "stoelindeling.view_seatingplans_rule",
+        },
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "seating_plans/create/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "stoelindeling.createSeatingPlan",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "seating_plans/:pk/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "stoelindeling.seatingPlan",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "seating_plans/:pk/edit/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "stoelindeling.editSeatingPlan",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "seating_plans/:pk/copy/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "stoelindeling.copySeatingPlan",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+      {
+        path: "seating_plans/:pk/delete/",
+        component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+        name: "stoelindeling.deleteSeatingPlan",
+        props: {
+          byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+        },
+      },
+    ],
+  }
+
diff --git a/aleksis/apps/stoelindeling/frontend/messages/de.json b/aleksis/apps/stoelindeling/frontend/messages/de.json
new file mode 100644
index 0000000000000000000000000000000000000000..4d4542c438bbc95914e3371e7219bbdc6f8580d2
--- /dev/null
+++ b/aleksis/apps/stoelindeling/frontend/messages/de.json
@@ -0,0 +1,6 @@
+{
+  "stoelindeling": {
+    "menu_title": "Sitzpläne"
+  }
+}
+
diff --git a/aleksis/apps/stoelindeling/frontend/messages/en.json b/aleksis/apps/stoelindeling/frontend/messages/en.json
new file mode 100644
index 0000000000000000000000000000000000000000..a95f9cc2015a4239ad6a880ad04ca623f220763f
--- /dev/null
+++ b/aleksis/apps/stoelindeling/frontend/messages/en.json
@@ -0,0 +1,6 @@
+{
+  "stoelindeling": {
+    "menu_title": "Seating plans"
+  }
+}
+
diff --git a/aleksis/apps/stoelindeling/views.py b/aleksis/apps/stoelindeling/views.py
index 3c7027803fbdcaf597882f63d335d42792a98e37..72ac1682e215a51fe909cb31b5ee51a6a0c2f1d1 100644
--- a/aleksis/apps/stoelindeling/views.py
+++ b/aleksis/apps/stoelindeling/views.py
@@ -10,6 +10,7 @@ from django_tables2 import SingleTableView
 from reversion.views import RevisionMixin
 from rules.contrib.views import PermissionRequiredMixin
 
+from aleksis.core.decorators import pwa_cache
 from aleksis.core.mixins import (
     AdvancedCreateView,
     AdvancedDeleteView,
@@ -24,6 +25,7 @@ from .tables import SeatingPlanTable
 from .util.perms import get_allowed_seating_plans
 
 
+@method_decorator(pwa_cache, name="dispatch")
 class SeatingPlanListView(PermissionRequiredMixin, SingleTableView):
     """Table of all seating plans."""
 
@@ -36,6 +38,7 @@ class SeatingPlanListView(PermissionRequiredMixin, SingleTableView):
         return get_allowed_seating_plans(self.request.user)
 
 
+@method_decorator(pwa_cache, name="dispatch")
 class SeatingPlanDetailView(PermissionRequiredMixin, DetailView):
     """Detail view for seating plans."""