diff --git a/.gitattributes b/.gitattributes
index 0601cb69d02130a712c0a48cf29ba3e193930304..c86405d3bf8e789fca771f69d8116c16193a6c6e 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4239,6 +4239,11 @@ SAS/LSMR/bin/lsmr_testdatabase -text
 SAS/LSMR/bin/lsmr_testldap -text
 SAS/LSMR/doc/LSMR.md -text
 SAS/LSMR/doc/package.dox -text
+SAS/LSMR/docker/README.md -text
+SAS/LSMR/docker/lsmr-postgres/Dockerfile -text
+SAS/LSMR/docker/lsmr-postgres/init.sql -text
+SAS/LSMR/docker/lsmr/Dockerfile -text
+SAS/LSMR/docker/lsmr/dbcreds.ini -text
 SAS/LSMR/src/CMakeLists.txt -text
 SAS/LSMR/src/lsmr/CMakeLists.txt -text
 SAS/LSMR/src/lsmr/__init__.py -text
@@ -4262,6 +4267,7 @@ SAS/LSMR/src/lsmr/lsmrapp/serializers/scheduling.py -text
 SAS/LSMR/src/lsmr/lsmrapp/serializers/specification.py -text
 SAS/LSMR/src/lsmr/lsmrapp/viewsets/CMakeLists.txt -text
 SAS/LSMR/src/lsmr/lsmrapp/viewsets/__init__.py -text
+SAS/LSMR/src/lsmr/lsmrapp/viewsets/lofar_viewset.py -text
 SAS/LSMR/src/lsmr/lsmrapp/viewsets/scheduling.py -text
 SAS/LSMR/src/lsmr/lsmrapp/viewsets/specification.py -text
 SAS/LSMR/src/lsmr/settings.py -text
diff --git a/SAS/LSMR/doc/LSMR.md b/SAS/LSMR/doc/LSMR.md
index 907432d367d36ab9aa1777c2fc583565a1cbac91..d41cdb56415cc2e018c0c7a076e231fbab841d9f 100644
--- a/SAS/LSMR/doc/LSMR.md
+++ b/SAS/LSMR/doc/LSMR.md
@@ -37,6 +37,7 @@ meetings with stakeholders.* TODO
 
 
 ### Testing
+
 TODO tests are missing 
 - *How do you run unit tests?* TODO
 - *How do you run integration tests?* TODO
@@ -45,8 +46,10 @@ TODO tests are missing
 ### Build & Deploy
 
 There is cmake integration for development work and testing. 
-For production deplyoment, the production database has to be configured in settings.py.
-This should be best served through Nginx or Apache, so you want to collect static files and reference the wsgi.py.  
+For production deployment, the production database has to be configured in settings.py.
+This should be best served through Nginx or Apache, so you want to collect static files and reference the wsgi.py.
+
+A docker environment is setup in ../docker, see ../docker/README.md
 
 - - -
 ## OPERATIONS
@@ -93,4 +96,4 @@ TODO
 
 ### Operations Documentation
 
-*e.g. Please refer to URL X for Operations Documentation*
\ No newline at end of file
+*e.g. Please refer to URL X for Operations Documentation*
diff --git a/SAS/LSMR/docker/README.md b/SAS/LSMR/docker/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6f11534aa1f72f882faa713d7975b9c2adc3d718
--- /dev/null
+++ b/SAS/LSMR/docker/README.md
@@ -0,0 +1,14 @@
+To build:
+
+	docker build -t lsmr-postgres lsmr-postgres
+	docker build -t lsmr [--build-arg BRANCH=LSMR-epic] lsmr
+
+To start the PostgreSQL container:
+
+	docker run [-it] --name=postgres-$USER --rm lsmr-postgres
+
+To start the LSMR container (exposing port 8001 to surf to):
+
+	docker run [-it] --rm -p 0.0.0.0:8001:8000 --link=postgres-$USER:postgres lsmr
+
+Note: "-it" allows one to abort the container with ^C.
diff --git a/SAS/LSMR/docker/lsmr-postgres/Dockerfile b/SAS/LSMR/docker/lsmr-postgres/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..7626c70899231474956bb81d762678156a6f9b5e
--- /dev/null
+++ b/SAS/LSMR/docker/lsmr-postgres/Dockerfile
@@ -0,0 +1,2 @@
+FROM library/postgres
+COPY init.sql /docker-entrypoint-initdb.d/
diff --git a/SAS/LSMR/docker/lsmr-postgres/init.sql b/SAS/LSMR/docker/lsmr-postgres/init.sql
new file mode 100644
index 0000000000000000000000000000000000000000..58a17e105a2ced5d8486090d54b1188b35b5c3b8
--- /dev/null
+++ b/SAS/LSMR/docker/lsmr-postgres/init.sql
@@ -0,0 +1,3 @@
+CREATE USER lsmr WITH SUPERUSER PASSWORD 'lsmr';
+CREATE DATABASE lsmr;
+GRANT ALL PRIVILEGES ON DATABASE lsmr TO lsmr;
diff --git a/SAS/LSMR/docker/lsmr/Dockerfile b/SAS/LSMR/docker/lsmr/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..94e7d4bb39f568431618b16d580d26ca7bffeb9d
--- /dev/null
+++ b/SAS/LSMR/docker/lsmr/Dockerfile
@@ -0,0 +1,43 @@
+FROM ubuntu:18.04
+
+# LOFAR branch to build
+ARG BRANCH=LSMR-epic
+
+# Export build-time variables to containters
+ENV BRANCH=$BRANCH
+
+RUN apt-get -y update && apt-get -y upgrade
+
+# LOFAR checkout and compile dependencies
+RUN apt-get -y install make cmake g++ subversion python3 git
+
+# LOFAR build dependencies
+RUN apt-get -y install liblog4cplus-dev python3-dev libldap2-dev libsasl2-dev
+RUN apt-get -y install python3-pip && pip3 install django djangorestframework django-filter django-auth-ldap coreapi python-ldap-test django-jsonforms django-json-widget "git+git://github.com/nnseva/django-jsoneditor.git" psycopg2-binary markdown ldap3 drf-yasg flex swagger-spec-validator
+
+# LOFAR test dependencies
+RUN apt-get -y install uuid-runtime iproute2 postgresql-10 openjdk-10-jre-headless
+RUN pip3 install testing.postgresql
+
+# Install LOFAR packages
+RUN mkdir /src && \
+    cd /src && \
+    svn co -N https://svn.astron.nl/LOFAR/branches/$BRANCH/ && \
+    cd $BRANCH/ && \
+    svn up CMake
+RUN mkdir -p /build/gnu_debug && cd /build/gnu_debug && cmake /src/$BRANCH/ -DBUILD_PACKAGES=LSMR -DCMAKE_INSTALL_PREFIX=/opt/lofar && make -j 8 && make -j 8 install
+
+# Configure authentication
+ADD dbcreds.ini /opt/lofar/etc/dbcredentials/lsmr.ini
+RUN echo "REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES']=[]" >> /opt/lofar/lib/python3.6/site-packages/lofar/sas/lsmr/lsmr/settings.py
+RUN echo "REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES']=[]" >> /opt/lofar/lib/python3.6/site-packages/lofar/sas/lsmr/lsmr/settings.py
+
+# Allow Django HTTP access
+EXPOSE 8000
+RUN echo "ALLOWED_HOSTS=['*']" >> /opt/lofar/lib/python3.6/site-packages/lofar/sas/lsmr/lsmr/settings.py
+
+# Hot patches
+
+# Run LOFAR app
+CMD bash -c 'source /opt/lofar/lofarinit.sh && lsmr'
+
diff --git a/SAS/LSMR/docker/lsmr/dbcreds.ini b/SAS/LSMR/docker/lsmr/dbcreds.ini
new file mode 100644
index 0000000000000000000000000000000000000000..bdec6c5ef772e27b51b34d809f262c1e5cbad2dd
--- /dev/null
+++ b/SAS/LSMR/docker/lsmr/dbcreds.ini
@@ -0,0 +1,5 @@
+[database:lsmr]
+host=postgres
+user=lsmr
+password=lsmr
+database=lsmr
diff --git a/SAS/LSMR/src/CMakeLists.txt b/SAS/LSMR/src/CMakeLists.txt
index 47ceed97437c8675741fec7ece3cb554e5c7b9e9..d5c88c6a6af8752bcb47af25afc7b7be70a577f7 100644
--- a/SAS/LSMR/src/CMakeLists.txt
+++ b/SAS/LSMR/src/CMakeLists.txt
@@ -15,6 +15,11 @@ find_python_module(django_auth_ldap REQUIRED)   # sudo apt-get install python3-d
 find_python_module(coreapi REQUIRED)            # sudo apt-get install python3-coreapi
 #find_python_module(jsoneditor REQUIRED)         # pip install "git+git://github.com/nnseva/django-jsoneditor.git"
 
+# modules for swagger API export
+find_python_module(drf_yasg REQUIRED)           # pip install drf-yasg
+find_python_module(flex REQUIRED)               # pip install flex
+find_python_module(swagger_spec_validator REQUIRED) # pip install swagger-spec-validator
+
 set(_py_files
     manage.py
     remakemigrations.py
diff --git a/SAS/LSMR/src/lsmr/lsmrapp/viewsets/CMakeLists.txt b/SAS/LSMR/src/lsmr/lsmrapp/viewsets/CMakeLists.txt
index 0a5d6a30f70d54d5f32cf4c081d340eaf1e63345..7bcf74595efb04b788425b8632a99833eb081bdf 100644
--- a/SAS/LSMR/src/lsmr/lsmrapp/viewsets/CMakeLists.txt
+++ b/SAS/LSMR/src/lsmr/lsmrapp/viewsets/CMakeLists.txt
@@ -3,6 +3,7 @@ include(PythonInstall)
 
 set(_py_files
     __init__.py
+    lofar_viewset.py
     specification.py
     scheduling.py
     )
diff --git a/SAS/LSMR/src/lsmr/lsmrapp/viewsets/lofar_viewset.py b/SAS/LSMR/src/lsmr/lsmrapp/viewsets/lofar_viewset.py
new file mode 100644
index 0000000000000000000000000000000000000000..a69bbc095fa9546bb65715eb6b2e3a923862bc8d
--- /dev/null
+++ b/SAS/LSMR/src/lsmr/lsmrapp/viewsets/lofar_viewset.py
@@ -0,0 +1,40 @@
+"""
+A viewset extended with annotation and other common generic behaviours.
+
+Adds the following functionality:
+- Swagger API annotation
+"""
+
+from rest_framework import viewsets
+from drf_yasg.utils import swagger_auto_schema
+
+class LOFARViewSet(viewsets.ModelViewSet):
+    """
+    If you're using format suffixes, make sure to also include
+    the `format=None` keyword argument for each action.
+    """
+
+    @swagger_auto_schema(responses={403: 'forbidden'})
+    def list(self, request):
+        return super(LOFARViewSet, self).list(request)
+
+    @swagger_auto_schema(responses={400: 'invalid specification', 403: 'forbidden'})
+    def create(self, request):
+        return super(LOFARViewSet, self).create(request)
+
+    @swagger_auto_schema(responses={403: 'forbidden', 404: 'not found'})
+    def retrieve(self, request, pk=None):
+        return super(LOFARViewSet, self).retrieve(request, pk)
+
+    @swagger_auto_schema(responses={400: 'invalid specification', 403: 'forbidden', 404: 'not found'})
+    def update(self, request, pk=None):
+        return super(LOFARViewSet, self).update(request, pk)
+
+    @swagger_auto_schema(responses={400: 'invalid specification', 403: 'forbidden', 404: 'not found'})
+    def partial_update(self, request, pk=None):
+        return super(LOFARViewSet, self).partial_update(request, pk)
+
+    @swagger_auto_schema(responses={403: 'forbidden', 404: 'not found'})
+    def destroy(self, request, pk=None):
+        return super(LOFARViewSet, self).destroy(request, pk)
+
diff --git a/SAS/LSMR/src/lsmr/lsmrapp/viewsets/scheduling.py b/SAS/LSMR/src/lsmr/lsmrapp/viewsets/scheduling.py
index 3c4cbbfa94f02e6909cef40134eabaa7cbf6bf2c..dad52d650b9300e1e63afbcf0bb82876cfaba020 100644
--- a/SAS/LSMR/src/lsmr/lsmrapp/viewsets/scheduling.py
+++ b/SAS/LSMR/src/lsmr/lsmrapp/viewsets/scheduling.py
@@ -4,70 +4,71 @@ This file contains the viewsets (based on the elsewhere defined data models and
 
 from django.shortcuts import get_object_or_404
 from rest_framework import viewsets
+from .lofar_viewset import LOFARViewSet
 from .. import models
 from .. import serializers
 
-class SubtaskConnectorViewSet(viewsets.ModelViewSet):
+class SubtaskConnectorViewSet(LOFARViewSet):
     queryset = models.SubtaskConnector.objects.all()
     serializer_class = serializers.SubtaskConnectorSerializer
 
 
-class SubtaskStateChoiceViewSet(viewsets.ModelViewSet):
+class SubtaskStateChoiceViewSet(LOFARViewSet):
     queryset = models.SubtaskStateChoice.objects.all()
     serializer_class = serializers.SubtaskStateChoiceSerializer
 
 
-class SubtaskTypeChoiceViewSet(viewsets.ModelViewSet):
+class SubtaskTypeChoiceViewSet(LOFARViewSet):
     queryset = models.SubtaskTypeChoice.objects.all()
     serializer_class = serializers.SubtaskTypeChoiceSerializer
 
 
-class StationTypeChoiceViewSet(viewsets.ModelViewSet):
+class StationTypeChoiceViewSet(LOFARViewSet):
     queryset = models.StationTypeChoice.objects.all()
     serializer_class = serializers.StationTypeChoiceSerializer
 
 
-class AlgorithmViewSet(viewsets.ModelViewSet):
+class AlgorithmViewSet(LOFARViewSet):
     queryset = models.Algorithm.objects.all()
     serializer_class = serializers.AlgorithmSerializer
 
 
-class ScheduleMethodViewSet(viewsets.ModelViewSet):
+class ScheduleMethodViewSet(LOFARViewSet):
     queryset = models.ScheduleMethod.objects.all()
     serializer_class = serializers.ScheduleMethodSerializer
 
 
-class SubtaskTemplateViewSet(viewsets.ModelViewSet):
+class SubtaskTemplateViewSet(LOFARViewSet):
     queryset = models.SubtaskTemplate.objects.all()
     serializer_class = serializers.SubtaskTemplateSerializer
 
 
-class DefaultSubtaskTemplateViewSet(viewsets.ModelViewSet):
+class DefaultSubtaskTemplateViewSet(LOFARViewSet):
     queryset = models.DefaultSubtaskTemplate.objects.all()
     serializer_class = serializers.DefaultSubtaskTemplateSerializer
 
 
-class DataproductSpecificationsTemplateViewSet(viewsets.ModelViewSet):
+class DataproductSpecificationsTemplateViewSet(LOFARViewSet):
     queryset = models.DataproductSpecificationsTemplate.objects.all()
     serializer_class = serializers.DataproductSpecificationsTemplateSerializer
 
 
-class DefaultDataproductSpecificationsTemplateViewSet(viewsets.ModelViewSet):
+class DefaultDataproductSpecificationsTemplateViewSet(LOFARViewSet):
     queryset = models.DefaultDataproductSpecificationsTemplate.objects.all()
     serializer_class = serializers.DefaultDataproductSpecificationsTemplateSerializer
 
 
-class SubtaskInputSelectionTemplateViewSet(viewsets.ModelViewSet):
+class SubtaskInputSelectionTemplateViewSet(LOFARViewSet):
     queryset = models.SubtaskInputSelectionTemplate.objects.all()
     serializer_class = serializers.SubtaskInputSelectionTemplateSerializer
 
 
-class DataproductFeedbackTemplateViewSet(viewsets.ModelViewSet):
+class DataproductFeedbackTemplateViewSet(LOFARViewSet):
     queryset = models.DataproductFeedbackTemplate.objects.all()
     serializer_class = serializers.DataproductFeedbackTemplateSerializer
 
 
-class SubtaskViewSet(viewsets.ModelViewSet):
+class SubtaskViewSet(LOFARViewSet):
     queryset = models.Subtask.objects.all()
     serializer_class = serializers.SubtaskSerializer
 
@@ -79,46 +80,46 @@ class SubtaskViewSet(viewsets.ModelViewSet):
             return models.Subtask.objects.all()
 
 
-class SubtaskInputViewSet(viewsets.ModelViewSet):
+class SubtaskInputViewSet(LOFARViewSet):
     queryset = models.SubtaskInput.objects.all()
     serializer_class = serializers.SubtaskInputSerializer
 
 
-class SubtaskOutputViewSet(viewsets.ModelViewSet):
+class SubtaskOutputViewSet(LOFARViewSet):
     queryset = models.SubtaskOutput.objects.all()
     serializer_class = serializers.SubtaskOutputSerializer
 
 
-class DataproductViewSet(viewsets.ModelViewSet):
+class DataproductViewSet(LOFARViewSet):
     queryset = models.Dataproduct.objects.all()
     serializer_class = serializers.DataproductSerializer
 
 
-class AntennaSetViewSet(viewsets.ModelViewSet):
+class AntennaSetViewSet(LOFARViewSet):
     queryset = models.AntennaSet.objects.all()
     serializer_class = serializers.AntennaSetSerializer
 
 
-class DataproductTransformViewSet(viewsets.ModelViewSet):
+class DataproductTransformViewSet(LOFARViewSet):
     queryset = models.DataproductTransform.objects.all()
     serializer_class = serializers.DataproductTransformSerializer
 
 
-class FilesystemViewSet(viewsets.ModelViewSet):
+class FilesystemViewSet(LOFARViewSet):
     queryset = models.Filesystem.objects.all()
     serializer_class = serializers.FilesystemSerializer
 
 
-class ClusterViewSet(viewsets.ModelViewSet):
+class ClusterViewSet(LOFARViewSet):
     queryset = models.Cluster.objects.all()
     serializer_class = serializers.ClusterSerializer
 
 
-class DataproductArchiveInfoViewSet(viewsets.ModelViewSet):
+class DataproductArchiveInfoViewSet(LOFARViewSet):
     queryset = models.DataproductArchiveInfo.objects.all()
     serializer_class = serializers.DataproductArchiveInfoSerializer
 
 
-class DataproductHashViewSet(viewsets.ModelViewSet):
+class DataproductHashViewSet(LOFARViewSet):
     queryset = models.DataproductHash.objects.all()
     serializer_class = serializers.DataproductHashSerializer
diff --git a/SAS/LSMR/src/lsmr/lsmrapp/viewsets/specification.py b/SAS/LSMR/src/lsmr/lsmrapp/viewsets/specification.py
index 53c9ebccd94aa56dfd9f3dfffd18b3c0e641b5d6..779b43a9811e4c196ab59a56a42c4def7423f978 100644
--- a/SAS/LSMR/src/lsmr/lsmrapp/viewsets/specification.py
+++ b/SAS/LSMR/src/lsmr/lsmrapp/viewsets/specification.py
@@ -4,85 +4,86 @@ This file contains the viewsets (based on the elsewhere defined data models and
 
 from django.shortcuts import get_object_or_404
 from rest_framework import viewsets
+from .lofar_viewset import LOFARViewSet
 from .. import models, serializers
 from rest_framework.renderers import BrowsableAPIRenderer, TemplateHTMLRenderer
 
-class TagsViewSet(viewsets.ModelViewSet):
+class TagsViewSet(LOFARViewSet):
     queryset = models.Tags.objects.all()
     serializer_class = serializers.TagsSerializer
 
 
-class GeneratorTemplateViewSet(viewsets.ModelViewSet):
+class GeneratorTemplateViewSet(LOFARViewSet):
     queryset = models.GeneratorTemplate.objects.all()
     serializer_class = serializers.GeneratorTemplateSerializer
 
 
-class DefaultGeneratorTemplateViewSet(viewsets.ModelViewSet):
+class DefaultGeneratorTemplateViewSet(LOFARViewSet):
     queryset = models.DefaultGeneratorTemplate.objects.all()
     serializer_class = serializers.DefaultGeneratorTemplateSerializer
 
 
-class SchedulingUnitTemplateViewSet(viewsets.ModelViewSet):
+class SchedulingUnitTemplateViewSet(LOFARViewSet):
     queryset = models.SchedulingUnitTemplate.objects.all()
     serializer_class = serializers.SchedulingUnitTemplateSerializer
 
 
-class DefaultSchedulingUnitTemplateViewSet(viewsets.ModelViewSet):
+class DefaultSchedulingUnitTemplateViewSet(LOFARViewSet):
     queryset = models.DefaultSchedulingUnitTemplate.objects.all()
     serializer_class = serializers.DefaultSchedulingUnitTemplateSerializer
 
 
-class TaskTemplateViewSet(viewsets.ModelViewSet):
+class TaskTemplateViewSet(LOFARViewSet):
     queryset = models.TaskTemplate.objects.all()
     serializer_class = serializers.TaskTemplateSerializer
 
 
-class DefaultTaskTemplateViewSet(viewsets.ModelViewSet):
+class DefaultTaskTemplateViewSet(LOFARViewSet):
     queryset = models.DefaultTaskTemplate.objects.all()
     serializer_class = serializers.DefaultTaskTemplateSerializer
 
 
-class WorkRelationSelectionTemplateViewSet(viewsets.ModelViewSet):
+class WorkRelationSelectionTemplateViewSet(LOFARViewSet):
     queryset = models.WorkRelationSelectionTemplate.objects.all()
     serializer_class = serializers.WorkRelationSelectionTemplateSerializer
 
 
-class DefaultWorkRelationSelectionTemplateViewSet(viewsets.ModelViewSet):
+class DefaultWorkRelationSelectionTemplateViewSet(LOFARViewSet):
     queryset = models.DefaultWorkRelationSelectionTemplate.objects.all()
     serializer_class = serializers.DefaultWorkRelationSelectionTemplateSerializer
 
 
-class RoleChoiceViewSet(viewsets.ModelViewSet):
+class RoleChoiceViewSet(LOFARViewSet):
     queryset = models.RoleChoice.objects.all()
     serializer_class = serializers.RoleChoiceSerializer
 
 
-class DatatypeChoiceViewSet(viewsets.ModelViewSet):
+class DatatypeChoiceViewSet(LOFARViewSet):
     queryset = models.DatatypeChoice.objects.all()
     serializer_class = serializers.DatatypeChoiceSerializer
 
 
-class DataformatChoiceViewSet(viewsets.ModelViewSet):
+class DataformatChoiceViewSet(LOFARViewSet):
     queryset = models.DataformatChoice.objects.all()
     serializer_class = serializers.DataformatChoiceSerializer
 
 
-class CopyReasonChoiceViewSet(viewsets.ModelViewSet):
+class CopyReasonChoiceViewSet(LOFARViewSet):
     queryset = models.CopyReasonChoice.objects.all()
     serializer_class = serializers.CopyReasonChoiceSerializer
 
 
-class TaskConnectorsViewSet(viewsets.ModelViewSet):
+class TaskConnectorsViewSet(LOFARViewSet):
     queryset = models.TaskConnectors.objects.all()
     serializer_class = serializers.TaskConnectorsSerializer
 
 
-class CycleViewSet(viewsets.ModelViewSet):
+class CycleViewSet(LOFARViewSet):
     queryset = models.Cycle.objects.all()
     serializer_class = serializers.CycleSerializer
 
 
-class ProjectViewSet(viewsets.ModelViewSet):
+class ProjectViewSet(LOFARViewSet):
     queryset = models.Project.objects.all()
     serializer_class = serializers.ProjectSerializer
 
@@ -94,12 +95,12 @@ class ProjectViewSet(viewsets.ModelViewSet):
             return models.Project.objects.all()
 
 
-class SchedulingSetViewSet(viewsets.ModelViewSet):
+class SchedulingSetViewSet(LOFARViewSet):
     queryset = models.SchedulingSet.objects.all()
     serializer_class = serializers.SchedulingSetSerializer
 
 
-class SchedulingUnitDraftViewSet(viewsets.ModelViewSet):
+class SchedulingUnitDraftViewSet(LOFARViewSet):
     queryset = models.SchedulingUnitDraft.objects.all()
     serializer_class = serializers.SchedulingUnitDraftSerializer
 
@@ -111,7 +112,7 @@ class SchedulingUnitDraftViewSet(viewsets.ModelViewSet):
             return models.SchedulingUnitDraft.objects.all()
 
 
-class SchedulingUnitBlueprintViewSet(viewsets.ModelViewSet):
+class SchedulingUnitBlueprintViewSet(LOFARViewSet):
     queryset = models.SchedulingUnitBlueprint.objects.all()
     serializer_class = serializers.SchedulingUnitBlueprintSerializer
 
@@ -123,7 +124,7 @@ class SchedulingUnitBlueprintViewSet(viewsets.ModelViewSet):
             return models.SchedulingUnitBlueprint.objects.all()
 
 
-class TaskDraftViewSet(viewsets.ModelViewSet):
+class TaskDraftViewSet(LOFARViewSet):
     queryset = models.TaskDraft.objects.all()
     serializer_class = serializers.TaskDraftSerializer
 
@@ -135,7 +136,7 @@ class TaskDraftViewSet(viewsets.ModelViewSet):
             return models.TaskDraft.objects.all()
 
 
-class TaskBlueprintViewSet(viewsets.ModelViewSet):
+class TaskBlueprintViewSet(LOFARViewSet):
     queryset = models.TaskBlueprint.objects.all()
     serializer_class = serializers.TaskBlueprintSerializer
 
@@ -147,7 +148,7 @@ class TaskBlueprintViewSet(viewsets.ModelViewSet):
             return models.TaskBlueprint.objects.all()
 
 
-class TaskRelationDraftViewSet(viewsets.ModelViewSet):
+class TaskRelationDraftViewSet(LOFARViewSet):
     queryset = models.TaskRelationDraft.objects.all()
     serializer_class = serializers.TaskRelationDraftSerializer
 
@@ -159,7 +160,7 @@ class TaskRelationDraftViewSet(viewsets.ModelViewSet):
             return models.TaskRelationDraft.objects.all()
 
 
-class TaskRelationBlueprintViewSet(viewsets.ModelViewSet):
+class TaskRelationBlueprintViewSet(LOFARViewSet):
     queryset = models.TaskRelationBlueprint.objects.all()
     serializer_class = serializers.TaskRelationBlueprintSerializer
 
@@ -178,23 +179,23 @@ class TaskRelationBlueprintViewSet(viewsets.ModelViewSet):
 # --- JSON
 
 
-class TaskBlueprintViewSetReactJSONform(viewsets.ModelViewSet):
+class TaskBlueprintViewSetReactJSONform(LOFARViewSet):
     queryset = models.TaskBlueprint.objects.all()
     serializer_class = serializers.TaskBlueprintSerializerReactJSONform
 
 
-class TaskBlueprintViewSetJSONeditor(viewsets.ModelViewSet):
+class TaskBlueprintViewSetJSONeditor(LOFARViewSet):
     queryset = models.TaskBlueprint.objects.all()
     serializer_class = serializers.TaskBlueprintSerializerJSONeditor
 
 
-class TaskBlueprintViewSetJSONeditorOnline(viewsets.ModelViewSet):
+class TaskBlueprintViewSetJSONeditorOnline(LOFARViewSet):
     queryset = models.TaskBlueprint.objects.all()
     serializer_class = serializers.TaskBlueprintSerializerJSONeditorOnline
 
 
 # # todo: this is experimental / for demo purposes. Remove or make functional.
-# class JSONEditorViewSet(viewsets.ModelViewSet):
+# class JSONEditorViewSet(LOFARViewSet):
 #      renderer_classes = [TemplateHTMLRenderer]
 #      template_name = 'react_jsonschema_form.html'
 #      queryset = models.TaskBlueprint.objects.all()
diff --git a/SAS/LSMR/src/lsmr/settings.py b/SAS/LSMR/src/lsmr/settings.py
index 61c60cde25e8d23de840201c3e63d6a91e035499..df738f0de392f40f8df7b3245c23adcc86466e50 100644
--- a/SAS/LSMR/src/lsmr/settings.py
+++ b/SAS/LSMR/src/lsmr/settings.py
@@ -52,7 +52,9 @@ INSTALLED_APPS = [
     'rest_framework',
     'django_jsonforms',
     'django_json_widget',
-    'jsoneditor'
+    'jsoneditor',
+    'drf_yasg',
+    'django_filters',
 ]
 
 MIDDLEWARE = [
@@ -116,7 +118,7 @@ DATABASES = {
         'ENGINE': 'django.db.backends.postgresql_psycopg2',
         'NAME': django_db_credentials.database,
         'USER': django_db_credentials.user,
-        'PASS': django_db_credentials.password,
+        'PASSWORD': django_db_credentials.password,
         'HOST': django_db_credentials.host,
         'PORT': django_db_credentials.port,
         }
@@ -136,6 +138,14 @@ REST_FRAMEWORK = {
     ],
     'PAGE_SIZE': 50,
     'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
+    'DEFAULT_FILTER_BACKENDS': (
+        # allows ?field=value filtering in URLs
+        # (fields allowed for filtering must be annotated in viewsets using filter_fields = ('field', ...))
+        'django_filters.rest_framework.DjangoFilterBackend',
+
+        # allows ?ordering=[-]field to order list results
+        'rest_framework.filters.OrderingFilter',
+    ),
 }
 
 # LDAP
diff --git a/SAS/LSMR/src/lsmr/urls.py b/SAS/LSMR/src/lsmr/urls.py
index 3232c894283582dd5af264b4e7201c364bcdf98d..efc0b5de2f5eee8485a723bcbec8f44b5ca5c1d1 100644
--- a/SAS/LSMR/src/lsmr/urls.py
+++ b/SAS/LSMR/src/lsmr/urls.py
@@ -15,22 +15,40 @@ Including another URLconf
 """
 
 from django.contrib import admin
-from django.urls import path
+from django.urls import path, re_path
 from django.views.generic.base import TemplateView
 
-from rest_framework import routers
+from rest_framework import routers, permissions
 from .lsmrapp import viewsets, models, serializers
 from rest_framework.documentation import include_docs_urls
-
+from drf_yasg.views import get_schema_view
+from drf_yasg import openapi
 
 #
 # Django style patterns
 #
 
+# schema for Swagger API
+swagger_schema_view = get_schema_view(
+   openapi.Info(
+      title="LOFAR Internal API",
+      default_version='v1',
+      description="ReST API for internal LOFAR services",
+      terms_of_service="",
+      contact=openapi.Contact(email="softwaresupport@astron.nl"),
+      license=openapi.License(name="GPL License v3"),
+   ),
+   validators=['flex', 'ssv'],
+   public=True,
+   permission_classes=(permissions.AllowAny,),
+)
 
 urlpatterns = [
     path('admin/', admin.site.urls),
-    path('docs/', include_docs_urls(title='LSMR API'))
+    path('docs/', include_docs_urls(title='LSMR API')),
+    re_path(r'^swagger(?P<format>\.json|\.yaml)$', swagger_schema_view.without_ui(cache_timeout=0), name='schema-json'),
+    path('swagger/', swagger_schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
+    path('redoc/', swagger_schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
 ]