diff --git a/ldvspec/ldvspec/settings/base.py b/ldvspec/ldvspec/settings/base.py
index 16345275b175c0ba95ff9658eaf21ab348bac7d6..bb6b9e6e4ff1148637ae752cc29e672da22f0d3a 100644
--- a/ldvspec/ldvspec/settings/base.py
+++ b/ldvspec/ldvspec/settings/base.py
@@ -130,6 +130,7 @@ REST_FRAMEWORK = {
     'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
     'PAGE_SIZE': 100
 }
+LOGIN_URL = '/ldvspec/accounts/login'
 LOGIN_REDIRECT_URL = '/ldvspec'
 # Recommended to use an environment variable to set the broker URL.
 CELERY_BROKER_URL = os.getenv("CELERY_BROKER_URL", "amqp://guest@localhost:5672")
diff --git a/ldvspec/lofardata/forms.py b/ldvspec/lofardata/forms.py
index faa5152bbb8f74145d54a9e5a9c728ff61583aa7..cb77f160e21be27d1091c60e7d1de0a88f607bc5 100644
--- a/ldvspec/lofardata/forms.py
+++ b/ldvspec/lofardata/forms.py
@@ -23,7 +23,7 @@ class WorkSpecificationForm(ModelForm):
         self.cleaned_data = super().clean()
         self.cleaned_data["filters"] = self._extract_filters()
         if not 'obs_id' in self.cleaned_data["filters"]:
-            raise ValidationError(["obs_id: This field is required."])
+            raise ValidationError(["SAS ID: This field is required."])
 
         return self.cleaned_data
 
diff --git a/ldvspec/lofardata/mixins.py b/ldvspec/lofardata/mixins.py
new file mode 100644
index 0000000000000000000000000000000000000000..0d18ee6797d9ce0deb99361f0fd91476d92e3833
--- /dev/null
+++ b/ldvspec/lofardata/mixins.py
@@ -0,0 +1,9 @@
+from django.contrib.auth.mixins import UserPassesTestMixin
+
+class CanAccessWorkSpecificationMixin(UserPassesTestMixin):
+    """
+    A mixin for checking whether a work specification can be accessed by a particular user
+    Works on all views that implement get_object (DetailView etc)
+    """
+    def test_func(self, **kwargs):
+        return self.get_object().can_be_accessed_by(self.request.user)
\ No newline at end of file
diff --git a/ldvspec/lofardata/models.py b/ldvspec/lofardata/models.py
index 9b034adb1861da373055c6692e7053b7fc425369..190b45c295a57b688f21aa89d383e96daec18b5f 100644
--- a/ldvspec/lofardata/models.py
+++ b/ldvspec/lofardata/models.py
@@ -147,6 +147,20 @@ class WorkSpecification(models.Model):
             return "Unknown"
         return self.created_by.get_full_name() if self.created_by.get_full_name() else self.created_by
 
+    def can_be_accessed_by(self, user):
+        """
+        Indicates whether this specification can be accessed (i.e., perform a CRUD operation) by the specified user
+        @param user: the user to check access for
+        @return: whether the specification can be accessed by the specified user, which is true if:
+        - the user is a staff member, OR
+        - the specification has not been added to the database yet (in which case, _state == adding) OR
+        - the specification was created by the user
+        """
+        return user.is_staff or self._state.adding or self.created_by_id == user.pk
+
+    def is_editable(self):
+        return self.submission_status != SUBMISSION_STATUS.SUBMITTED and self.submission_status != SUBMISSION_STATUS.DEFINING
+
     def __str__(self):
         return str(self.id) + ' - ' + str(self.filters) + " (" + str(self.created_on) + ")"
 
diff --git a/ldvspec/lofardata/static/lofardata/styling/dias.css b/ldvspec/lofardata/static/lofardata/styling/dias.css
index 1eff72969e33b6167a90b13cb68fe8b9cbcfd09d..2d245fae67082007366d918c29037baa82a64ec5 100644
--- a/ldvspec/lofardata/static/lofardata/styling/dias.css
+++ b/ldvspec/lofardata/static/lofardata/styling/dias.css
@@ -128,10 +128,7 @@ td, th {
     align-items: center;
 }
 
-.icon-after:after, .input--date:after,
-.icon:before,
-.section-toggle-invert + label:before,
-.section-toggle + label:before {
+.icon-after:after, .input--date:after, .icon:before, .section-toggle-invert + label:before, .section-toggle + label:before {
     -moz-osx-font-smoothing: grayscale;
     -webkit-font-smoothing: antialiased;
     display: inline-block;
@@ -168,9 +165,10 @@ td, th {
     position: absolute;
 }
 
-.icon.icon--alert:before, .section-toggle-invert + label.icon--alert:before, .section-toggle + label.icon--alert:before {
-    color: var(--warning);
-    opacity: 1;
+.icon--stacked {
+    position: absolute;
+    margin-left: -0.5rem;
+    transform: scale(0.8);
 }
 
 .icon--square {
@@ -185,31 +183,36 @@ td, th {
     color: inherit;
 }
 
-.icon--color-bright:before {
-    color: var(--light-grey);
+.icon--success:before {
+    color: var(--green);
+    opacity: 1;
 }
 
-.icon--disabled {
-    color: var(--faded);
+.icon--primary:before {
+    color: var(--primary);
+    opacity: 1;
 }
 
-.icon--disabled:before {
-    color: var(--faded);
+.icon--alert:before {
+    color: var(--warning);
+    opacity: 1;
 }
 
-.icon-after--disabled {
-    color: var(--faded);
+.icon--error:before {
+    color: var(--red);
+    opacity: 1;
 }
 
-.icon-after--disabled:after {
-    color: var(--faded);
+.icon--color-bright:before {
+    color: var(--light-grey);
+    opacity: 1;
 }
 
-.icon-after--disabled {
+.icon--disabled, .icon-after--disabled {
     color: var(--faded);
 }
 
-.icon-after--disabled:after {
+.icon--disabled:before, .icon--disabled:after, .icon-after--disabled:before, .icon-after--disabled:after {
     color: var(--faded);
 }
 
@@ -1041,10 +1044,9 @@ html {
     color: var(--text);
 }
 
-
 @media (max-width: 1440px) {
     html {
-        font-size: 18px;
+        font-size: 14px;
     }
 }
 
@@ -1068,6 +1070,11 @@ h1 {
     margin: 0 0 1.5rem;
 }
 
+.h1--no-margin,
+h1--no-margin {
+    margin: 0;
+}
+
 .h2,
 h2 {
     font-size: 1.25rem;
@@ -2743,6 +2750,10 @@ input.section-toggle-invert:checked ~ .section-wrapper {
     margin-right: 0;
 }
 
+.button--icon-button .icon:before.button--inline, .button--icon-button .section-toggle + label:before.button--inline, .button--icon-button .section-toggle-invert + label:before.button--inline {
+    padding: 0;
+}
+
 .button .spinner {
     line-height: 1;
 }
@@ -2984,6 +2995,14 @@ input.section-toggle-invert:checked ~ .section-wrapper {
     border: 2px solid var(--grey);
 }
 
+.button--disabled.button--primary .icon.icon--success:before, .button--disabled.button--primary .section-toggle + label.icon--success:before, .button--disabled.button--primary .section-toggle-invert + label.icon--success:before {
+    color: var(--green);
+}
+
+.button--disabled.button--primary .icon.icon--primary:before, .button--disabled.button--primary .section-toggle + label.icon--primary:before, .button--disabled.button--primary .section-toggle-invert + label.icon--primary:before {
+    color: var(--primary);
+}
+
 .button--disabled.button--primary .icon:before, .button--disabled.button--primary .section-toggle + label:before, .button--disabled.button--primary .section-toggle-invert + label:before {
     color: var(--text);
 }
@@ -2994,6 +3013,26 @@ input.section-toggle-invert:checked ~ .section-wrapper {
     border: 2px solid var(--grey);
 }
 
+.button--disabled.button--primary:hover .icon.icon--success:before, .button--disabled.button--primary:hover .section-toggle + label.icon--success:before, .button--disabled.button--primary:hover .section-toggle-invert + label.icon--success:before {
+    color: var(--green);
+    opacity: 1;
+}
+
+.button--disabled.button--primary:hover .icon.icon--primary:before, .button--disabled.button--primary:hover .section-toggle + label.icon--primary:before, .button--disabled.button--primary:hover .section-toggle-invert + label.icon--primary:before {
+    color: var(--primary);
+    opacity: 1;
+}
+
+.button--disabled.button--primary:hover .icon.icon--alert:before, .button--disabled.button--primary:hover .section-toggle + label.icon--alert:before, .button--disabled.button--primary:hover .section-toggle-invert + label.icon--alert:before {
+    color: var(--warning);
+    opacity: 1;
+}
+
+.button--disabled.button--primary:hover .icon.icon--error:before, .button--disabled.button--primary:hover .section-toggle + label.icon--error:before, .button--disabled.button--primary:hover .section-toggle-invert + label.icon--error:before {
+    color: var(--red);
+    opacity: 1;
+}
+
 .button--disabled.button--primary:hover .icon:before, .button--disabled.button--primary:hover .section-toggle + label:before, .button--disabled.button--primary:hover .section-toggle-invert + label:before {
     color: var(--text);
 }
@@ -3709,3 +3748,23 @@ input.section-toggle-invert:checked ~ .section-wrapper {
 .custom__input--fixed-width {
     width: 12rem;
 }
+
+.custom--action-button {
+    padding: 0.025rem 0 0 0;
+    border: none;
+    position: absolute;
+    font-size: initial;
+    min-width: max-content;
+}
+
+.custom--group {
+    background: var(--border--light);
+    border: 2px solid transparent;
+    padding: 0.75rem;
+    margin-bottom: 2rem;
+    border-radius: 0.75rem;
+}
+
+.custom--group-actions {
+    padding-left: 1rem;
+}
diff --git a/ldvspec/lofardata/templates/lofardata/index.html b/ldvspec/lofardata/templates/lofardata/index.html
index 4e649f613e267babf6cf5458f94d7a70137e5b0a..4b7ed7683d8281d81d70e22cae3d43e59080a804 100644
--- a/ldvspec/lofardata/templates/lofardata/index.html
+++ b/ldvspec/lofardata/templates/lofardata/index.html
@@ -56,17 +56,24 @@
                         <div class="table__cell">
                             {% if specification.get_submission_status_display == "submitted" %}
                                 {% define "green" as badgecolor %}
+                                {% define "The work specification has been succcesfully processed in ATDB." as badgeTitle %}
                             {% endif %}
                             {% if specification.get_submission_status_display == "error" %}
                                 {% define "red" as badgecolor %}
+                                {% define "Retrieving the files to process resulted in an error. Please reports this to the support helpdesk." as badgeTitle %}
                             {% endif %}
                             {% if specification.get_submission_status_display == "defining" %}
                                 {% define "secondary" as badgecolor %}
+                                {% define "The work specification has been send to ATDB but has not yet been processed there." as badgeTitle %}
                             {% endif %}
                             {% if specification.get_submission_status_display == "undefined"  or specification.get_submission_status_display == "not submitted" %}
                                 {% define "primary" as badgecolor %}
+                                {% define "The work specification has been created but has not yet been send to ATDB for processing." as badgeTitle %}
                             {% endif %}
-                            <div class="badge badge--{{ badgecolor }} margin-top" test-id="submission-status">{{ specification.get_submission_status_display }}</div>
+                            <div class="badge badge--{{ badgecolor }} margin-top" title="{{ badgeTitle }}"
+                                 test-id="submission-status">
+                                {{ specification.get_submission_status_display }}
+                            </div>
                         </div>
                         <div class="table__cell table__cell--truncate">
                             <a href="{{ specification.processing_site.url }}"
@@ -105,46 +112,58 @@
                         <!-- Actions -->
                         <div class="table__cell">
                             <div class="flex-wrapper flex-wrapper--row">
-                                <a class="button--icon-button margin-left margin-right"
-                                   href="{% url 'specification-update' pk=specification.pk %}"
-                                   title="Edit this work specification">
-                                    <span class="icon icon--pen"></span>
-                                </a>
-
                                 {% if specification.successor.count %}
-                                    <a class="link--disabled button--icon-button margin-right"
+                                    <a class="link--disabled button--icon-button margin-left"
                                        title="Cannot delete this work specification since it has successors. Delete them first">
                                         <span class="icon icon--color-inherit icon--trash-alt"></span>
                                     </a>
                                 {% else %}
-                                    <a class="link--red button--icon-button margin-right"
+                                    <a class="button--icon-button margin-left"
                                        href="{% url 'specification-delete' pk=specification.pk %}"
                                        title="Delete this work specification">
                                         <span class="icon icon--color-inherit icon--trash-alt"></span>
                                     </a>
                                 {% endif %}
 
+                                {% if not specification.is_editable %}
+                                    <a class="link--disabled button--icon-button margin-left margin-right"
+                                       title="Tasks already present in ATDB">
+                                    <span class="icon icon--color-inherit icon--pen">
+                                        <span class="icon icon--color-inherit icon--stacked icon--success icon--check"></span>
+                                    </span>
+                                    </a>
+                                {% else %}
+                                    <a class="button--icon-button margin-left margin-right"
+                                       href="{% url 'specification-update' pk=specification.pk %}"
+                                       title="Edit this work specification">
+                                        <span class="icon icon--pen"></span>
+                                    </a>
+                                {% endif %}
+
                                 <form method="post" action="{% url 'workspecification-submit' pk=specification.pk %}">
                                     {% csrf_token %}
 
-                                    {% if specification.get_submission_status_display == "submitted" or specification.get_submission_status_display == "defining" %}
+                                    {% if not specification.is_editable %}
                                         <a class="link--disabled button--icon-button"
                                            title="Tasks already present in ATDB">
-                                            <span class="icon icon--color-inherit icon--play"></span>
+                                            <span class="icon icon--color-inherit icon--play">
+                                                <span class="icon icon--color-inherit icon--stacked icon--success icon--check"></span>
+                                            </span>
                                         </a>
                                     {% elif specification.inputs.surls|length == 0 %}
                                         <a class="link--disabled button--icon-button"
                                            title="Cannot submit this task to ATDB since it does not contain any files">
-                                            <span class="icon icon--color-inherit icon--play"></span>
+                                            <span class="icon icon--color-inherit icon--play">
+                                                <span class="icon icon--color-inherit icon--stacked icon--primary icon--file"></span>
+                                            </span>
                                         </a>
                                     {% else %}
-                                        <button type="submit" class="button--icon-button" test-id="submit-to-atdb-{{ specification.pk }}" title="Submit to ATDB">
+                                        <button type="submit" class="custom--action-button button button--icon-button"
+                                                test-id="submit-to-atdb-{{ specification.pk }}" title="Submit to ATDB">
                                             <span class="icon icon--play"></span>
                                         </button>
                                     {% endif %}
-
                                 </form>
-
                             </div>
                         </div>
                     </div>
diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html b/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html
index 711892e02ce18d941520e3b21e8d581127187eb0..a0d3be019dfdd37fcacc1408aa6a45f5aa705cb0 100644
--- a/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html
+++ b/ldvspec/lofardata/templates/lofardata/workspecification/create_update.html
@@ -26,7 +26,7 @@
                             <h3 class="text text--primary text--title">Selection</h3>
                             <div class="flex-wrapper flex-wrapper--row" id="div_id_processing_site">
                                 <div class="flex-wrapper flex-wrapper--row custom__input--fixed-min-width">
-                                    <label class="input__label">{{ form.processing_site.label }}</label>
+                                    <label class="input__label">{{ form.processing_site.label }}*</label>
                                     <a class="tooltip-dias tooltip-dias-right custom--tooltip"
                                        data-tooltip="{{ form.processing_site.help_text }}">m</a>
                                 </div>
@@ -122,7 +122,7 @@
 
                         <!-- Filter fields -->
                         <div class="custom--div-margin">
-                            <h3 class="text text--primary text--title">Filters*</h3>
+                            <h3 class="text text--primary text--title">Filters</h3>
                             {% for filter in filters %}
                                 {% if filter.filter_type == 'Free' %}
                                     <div class="flex-wrapper">
diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/dataset_size_info.html b/ldvspec/lofardata/templates/lofardata/workspecification/dataset_size_info.html
index 059f3a583a70aa7d7d87a84d470b5347bc8aa54c..af606dbc853db6e72c3d6838355de6056e8ba3ca 100644
--- a/ldvspec/lofardata/templates/lofardata/workspecification/dataset_size_info.html
+++ b/ldvspec/lofardata/templates/lofardata/workspecification/dataset_size_info.html
@@ -39,7 +39,7 @@
         let data = [];
         for (let i = 0; i < {{ n_bins }}; i++) {
             let entry = {}
-            entry[xaxis_key] = (xaxis_values[i - 1] ? xaxis_values[i - 1] : 0) + " - " + xaxis_values[i]
+            entry[xaxis_key] = xaxis_values[i] === xaxis_values[i + 1] ? xaxis_values[i] : xaxis_values[i] + " - " + xaxis_values[i + 1]
             entry[yaxis_key] = yaxis_values[i]
             data[i] = entry
         }
diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/detail.html b/ldvspec/lofardata/templates/lofardata/workspecification/detail.html
index 797c0e6472a6dff698d35de98cd701f54151ea1c..95c204c8a48491a5557065bf038aeeb92106d43b 100644
--- a/ldvspec/lofardata/templates/lofardata/workspecification/detail.html
+++ b/ldvspec/lofardata/templates/lofardata/workspecification/detail.html
@@ -14,10 +14,6 @@
 
                         <span class="margin-top">Work Specification {{ object.pk }}</span>
 
-                        <a class="button button--secondary button--icon-button margin-left margin-right"
-                           href="{% url 'specification-update' pk=object.pk %}" title="Edit this work specification">
-                            <span class="icon icon--pen"></span>
-                        </a>
 
                         {% if object.successor.count %}
                             <a class="button button--icon-button button--primary button--disabled margin-right"
@@ -25,27 +21,46 @@
                                 <span class="icon icon--trash-alt"></span>
                             </a>
                         {% else %}
-                            <a class="button button--secondary button--red button--icon-button margin-right"
+                            <a class="button button--secondary button--icon-button margin-left"
                                href="{% url 'specification-delete' pk=object.pk %}"
                                title="Delete this work specification">
                                 <span class="icon icon--trash-alt"></span>
                             </a>
                         {% endif %}
 
+                        {% if not object.is_editable %}
+                            <a class="button button--primary button--disabled button--icon-button margin-left margin-right"
+                               title="Tasks already present in ATDB">
+                            <span class="icon icon--pen">
+                                <span class="icon icon--color-inherit icon--stacked icon--success icon--check"></span>
+                            </span>
+                            </a>
+                        {% else %}
+                            <a class="button button--secondary button--icon-button margin-left margin-right"
+                               href="{% url 'specification-update' pk=object.pk %}"
+                               title="Edit this work specification">
+                                <span class="icon icon--pen"></span>
+                            </a>
+                        {% endif %}
+
                         <form method="post" action="{% url 'workspecification-submit' pk=object.pk %}">
                             {% csrf_token %}
 
-                            {% if object.get_submission_status_display == "submitted" or object.get_submission_status_display == "defining" %}
+                            {% if not object.is_editable %}
                                 <a class="button button--icon-button button--primary button--disabled"
                                    title="Tasks already present in ATDB"
                                    href="#">
-                                    <span class="icon icon--play"></span>
+                                    <span class="icon icon--color-inherit icon--play">
+                                        <span class="icon icon--color-inherit icon--stacked icon--success icon--check"></span>
+                                    </span>
                                 </a>
                             {% elif number_of_files == 0 %}
                                 <a class="button button--icon-button button--primary button--disabled"
                                    title="No files to process in ATDB"
                                    href="#">
-                                    <span class="icon icon--play"></span>
+                                    <span class="icon icon--play">
+                                        <span class="icon icon--color-inherit icon--stacked icon--primary icon--file"></span>
+                                    </span>
                                 </a>
                             {% else %}
                                 <button type="submit"
@@ -118,17 +133,24 @@
                                 <div class="table__cell">
                                     {% if object.get_submission_status_display == "submitted" %}
                                         {% define "green" as badgecolor %}
+                                        {% define "The work specification has been succcesfully processed in ATDB." as badgeTitle %}
                                     {% endif %}
                                     {% if object.get_submission_status_display == "error" %}
                                         {% define "red" as badgecolor %}
+                                        {% define "Retrieving the files to process resulted in an error. Please reports this to the support helpdesk." as badgeTitle %}
                                     {% endif %}
                                     {% if object.get_submission_status_display == "defining" %}
                                         {% define "secondary" as badgecolor %}
+                                        {% define "The work specification has been send to ATDB but has not yet been processed there." as badgeTitle %}
                                     {% endif %}
                                     {% if object.get_submission_status_display == "undefined"  or object.get_submission_status_display == "not submitted" %}
                                         {% define "primary" as badgecolor %}
+                                        {% define "The work specification has been created but has not yet been send to ATDB for processing." as badgeTitle %}
                                     {% endif %}
-                                    <div class="badge badge--{{ badgecolor }}" test-id="submission-status">{{ object.get_submission_status_display }}</div>
+                                    <div class="badge badge--{{ badgecolor }} margin-top" test-id="submission-status"
+                                         title="{{ badgeTitle }}">
+                                        {{ object.get_submission_status_display }}
+                                    </div>
                                 </div>
                             </div>
 
@@ -149,30 +171,30 @@
                                 </div>
 
 
-                                <div class="table__row table__row--dark table__row--padding">
-                                    <div class="table__cell table__cell--title">Data Product Information</div>
-                                    <div class="table__cell">
-                                        <a class="button button--icon-button custom--button-no-padding"
-                                           href="{% url 'specification-dataproducts' object.pk %}">
-                                            <span class="icon icon--file-alt"></span>
-                                        </a>
-                                    </div>
-                                </div>
-
-                                <div class="table__row table__row--dark table__row--padding">
-                                    <div class="table__cell table__cell--title">Number of files</div>
-                                    {% if number_of_files == 0 %}
+                                {% if number_of_files == 0 %}
+                                    <div class="table__row table__row--dark table__row--padding">
+                                        <div class="table__cell table__cell--title">Number of files</div>
                                         <div class="table__cell">
-                                            <a class="tooltip-dias tooltip-dias-right tooltip-dias--without-margin tooltip-dias--red "
+                                            <a class="tooltip-dias tooltip-dias-right tooltip-dias--without-margin "
                                                data-tooltip="No files found for this SAS ID">m</a>
                                         </div>
-                                    {% else %}
-                                        <div class="table__cell">{{ number_of_files }}</div>
-                                    {% endif %}
-                                </div>
+                                    </div>
+                                {% else %}
+                                    <div class="table__row table__row--dark table__row--padding">
+                                        <div class="table__cell table__cell--title">Data Product Information</div>
+                                        <div class="table__cell">
+                                            <a class="button button--icon-button custom--button-no-padding"
+                                               href="{% url 'specification-dataproducts' object.pk %}">
+                                                <span class="icon icon--file-alt"></span>
+                                            </a>
+                                        </div>
+                                    </div>
 
+                                    <div class="table__row table__row--dark table__row--padding">
+                                        <div class="table__cell table__cell--title">Number of files</div>
+                                        <div class="table__cell">{{ number_of_files }}</div>
+                                    </div>
 
-                                {% if number_of_files > 0 %}
                                     <div class="table__row table__row--dark table__row--padding">
                                         <div class="table__cell table__cell--title">Files per task</div>
                                         {% if object.batch_size == 0 %}
diff --git a/ldvspec/lofardata/templates/lofardata/workspecification/tasks.html b/ldvspec/lofardata/templates/lofardata/workspecification/tasks.html
index c679e7c9afd1b49331584d2b3568738982024a67..5333c275e46ca6a0d6a5b53c5c15f9cc24634c38 100644
--- a/ldvspec/lofardata/templates/lofardata/workspecification/tasks.html
+++ b/ldvspec/lofardata/templates/lofardata/workspecification/tasks.html
@@ -18,7 +18,7 @@
                     {% for related_task in object.related_tasks %}
                         <dd>
                             <a class="button button--link"
-                               href="{{ object.processing_site.url }}tasks/{{ related_task }}">
+                               href="{{ object.processing_site.url }}task_details/{{ related_task }}/1">
                                 {{ related_task }}
                             </a>
                         </dd>
diff --git a/ldvspec/lofardata/templates/registration/login.html b/ldvspec/lofardata/templates/registration/login.html
index 823908ab48cefe13049cd1bd6be3394255b3607a..e18c3ed2fd1826f848da6c772da54ce2ed2b9b25 100644
--- a/ldvspec/lofardata/templates/registration/login.html
+++ b/ldvspec/lofardata/templates/registration/login.html
@@ -38,6 +38,8 @@
                         <input id="id_password" class="input maxwidth-input" name="password" type="password" required>
                     </div>
 
+                    <input type="hidden" name="next" value="{{ request.GET.next }}" />
+
                     <div class="flex-wrapper flex-wrapper--end">
                         <button type="submit" class="button button--primary margin-right">Sign in</button>
                     </div>
diff --git a/ldvspec/lofardata/tests/test_dataproductinfo.py b/ldvspec/lofardata/tests/test_dataproductinfo.py
index 0a2460f25e853976ce4431303082c5e87c0e99c1..270acd3cdd4eeee1c27f42cb0cf8e23ee97422a9 100644
--- a/ldvspec/lofardata/tests/test_dataproductinfo.py
+++ b/ldvspec/lofardata/tests/test_dataproductinfo.py
@@ -124,6 +124,10 @@ class RetrieveDataProductInformation(unittest.TestCase):
         number_of_dataproducts = DataProduct.objects.count()
         self.assertEqual(number_of_dataproducts, len(test_objects))
 
+    def test_no_database_entry(self):
+        actual = retrieve_combined_information('not_existent')
+        self.assertDictEqual(actual, {})
+
     def test_single_database_entry(self):
         actual = retrieve_combined_information('12345')
         self.assertEqual(actual['dataproduct_source'], ['lofar'])
diff --git a/ldvspec/lofardata/tests/test_inputs_processor.py b/ldvspec/lofardata/tests/test_inputs_processor.py
index 4101905cf51b048c6c68991dc57ba8bc42891aca..39712417094520b2a6fa52bec57cf497988f4770 100644
--- a/ldvspec/lofardata/tests/test_inputs_processor.py
+++ b/ldvspec/lofardata/tests/test_inputs_processor.py
@@ -36,6 +36,7 @@ class ComputeInputsHistogram(unittest.TestCase):
         self.assertListEqual([1, 2, 2, 0, 0, 1], counts)
         self.assertListEqual(['20.333GB', '25.300GB', '30.267GB', '35.234GB', '40.201GB', '45.168GB', '50.135GB'], bins)
 
+
     def test_single_range(self):
         test_data = {"surls": [{"size": 1, "surl": "test"},
                                {"size": 1, "surl": "test"},
@@ -53,6 +54,7 @@ class ComputeInputsHistogram(unittest.TestCase):
         self.assertListEqual([6], counts)
         self.assertListEqual(['0.500B', '1.500B'], bins)
 
+
     def test_extreme_wide_range(self):
         test_data = {"surls": [{"size": 1, "surl": "test"},
                                {"size": 100000, "surl": "test"},
@@ -71,6 +73,7 @@ class ComputeInputsHistogram(unittest.TestCase):
         self.assertListEqual(['1.000B', '148.030PB', '296.059PB', '444.089PB', '592.119PB', '740.149PB', '888.178PB'],
                              bins)
 
+
     def test_two_ranges(self):
         test_data = {"surls": [{"size": 97873920, "surl": "test"},
                                {"size": 97873920, "surl": "test"},
diff --git a/ldvspec/lofardata/tests/test_workspecification_access.py b/ldvspec/lofardata/tests/test_workspecification_access.py
new file mode 100644
index 0000000000000000000000000000000000000000..c4f8c47a23c82a5baa7f29b9c38e8875d23af4a4
--- /dev/null
+++ b/ldvspec/lofardata/tests/test_workspecification_access.py
@@ -0,0 +1,34 @@
+import unittest
+
+from django.contrib.auth.models import User
+from lofardata.models import WorkSpecification
+
+
+class WorkSpecificationAccess(unittest.TestCase):
+    def test_access_by_staff(self):
+        staff_user = User(pk=1, is_staff=True)
+        owner = User(pk=2, is_staff=False)
+        workspecification = WorkSpecification(created_by=owner)
+        workspecification._state.adding = False # existing workspecification, exists in database
+        self.assertTrue(workspecification.can_be_accessed_by(staff_user))
+
+    def test_access_by_user_with_permission(self):
+        owner = User(pk=1, is_staff=False)
+        workspecification = WorkSpecification(created_by=owner)
+        workspecification._state.adding = False # existing workspecification, exists in database
+        self.assertTrue(workspecification.can_be_accessed_by(owner))
+
+    def test_access_by_user_without_permission(self):
+        owner = User(pk=1, is_staff=False)
+        other_user = User(pk=2, is_staff=False)
+        workspecification = WorkSpecification(created_by=owner)
+        workspecification._state.adding = False # existing workspecification, exists in database
+        self.assertFalse(workspecification.can_be_accessed_by(other_user))
+
+    def test_access_when_new(self):
+        owner = User(pk=1, is_staff=False)
+        other_user = User(pk=2, is_staff=False)
+        workspecification = WorkSpecification(created_by=owner)
+        workspecification._state.adding = True # newly created, not added to the database yet
+        self.assertTrue(workspecification.can_be_accessed_by(other_user))
+
diff --git a/ldvspec/lofardata/tests/test_workspecification_creation.py b/ldvspec/lofardata/tests/test_workspecification_creation.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f40c72452b2862d0b899d7035cca1ef9b08df9b
--- /dev/null
+++ b/ldvspec/lofardata/tests/test_workspecification_creation.py
@@ -0,0 +1,25 @@
+import unittest
+
+from django.contrib.auth.models import User
+
+from lofardata.models import WorkSpecification
+from lofardata.views import set_post_submit_values
+
+class WorkSpecificationCreation(unittest.TestCase):
+    def test_set_created_by_when_already_set(self):
+
+        existing_user = User(pk=1, username='existing')
+        new_user = User(pk=2, username='new')
+
+        specification = WorkSpecification(created_by=existing_user)
+        set_post_submit_values(specification, new_user)
+
+        self.assertEqual(specification.created_by, existing_user)
+
+    def test_set_created_by_when_not_set(self):
+        new_user = User(pk=2, username='new')
+
+        specification = WorkSpecification()
+        set_post_submit_values(specification, new_user)
+
+        self.assertEqual(specification.created_by, new_user)
\ No newline at end of file
diff --git a/ldvspec/lofardata/tests/test_workspecification_editable.py b/ldvspec/lofardata/tests/test_workspecification_editable.py
new file mode 100644
index 0000000000000000000000000000000000000000..ef359462724d9b8a768f25859261716cb9ffa656
--- /dev/null
+++ b/ldvspec/lofardata/tests/test_workspecification_editable.py
@@ -0,0 +1,20 @@
+import unittest
+
+from lofardata.models import WorkSpecification, SUBMISSION_STATUS
+
+class WorkSpecificationEditable(unittest.TestCase):
+    def test_not_editable_submitted(self):
+        specification = WorkSpecification(submission_status=SUBMISSION_STATUS.SUBMITTED)
+        self.assertFalse(specification.is_editable())
+
+    def test_not_editable_defining(self):
+        specification = WorkSpecification(submission_status=SUBMISSION_STATUS.DEFINING)
+        self.assertFalse(specification.is_editable())
+
+    def test_editable_not_submitted(self):
+        specification = WorkSpecification(submission_status=SUBMISSION_STATUS.NOT_SUBMITTED)
+        self.assertTrue(specification.is_editable())
+
+    def test_editable_error(self):
+        specification = WorkSpecification(submission_status=SUBMISSION_STATUS.ERROR)
+        self.assertTrue(specification.is_editable())
\ No newline at end of file
diff --git a/ldvspec/lofardata/view_helpers/dataproductinfo.py b/ldvspec/lofardata/view_helpers/dataproductinfo.py
index 5e68f025b1a71fa0183888f01251c3c056038d7b..50f7ab89c7aa9bcea2c56a1cc1885591cbde1f01 100644
--- a/ldvspec/lofardata/view_helpers/dataproductinfo.py
+++ b/ldvspec/lofardata/view_helpers/dataproductinfo.py
@@ -11,6 +11,10 @@ def retrieve_combined_information(sas_id):
                                                                      'antenna_set',
                                                                      'instrument_filter',
                                                                      'dysco_compression').distinct()
+
+    if len(data_products) == 0:
+        return {}
+
     combined_data_products_on_key = combine_dataproducts_on_key(data_products)
 
     dysco_compressions = combined_data_products_on_key['dysco_compression']
diff --git a/ldvspec/lofardata/views.py b/ldvspec/lofardata/views.py
index cdb895968428e5c5c5ddf50ed530ad1a8336da64..ecf0799379fb30b63a3855e9700d2eaa2d5c0939 100644
--- a/ldvspec/lofardata/views.py
+++ b/ldvspec/lofardata/views.py
@@ -1,5 +1,6 @@
 import time
 
+from django.contrib.auth.mixins import LoginRequiredMixin
 from django.contrib.auth.models import User
 from django.core.exceptions import ObjectDoesNotExist
 from django.http import HttpResponseRedirect
@@ -14,6 +15,7 @@ from rest_framework.reverse import reverse_lazy
 from rest_framework.schemas.openapi import AutoSchema
 
 from .forms import WorkSpecificationForm
+from .mixins import CanAccessWorkSpecificationMixin
 from .models import (
     ATDBProcessingSite,
     DataProduct,
@@ -64,6 +66,11 @@ def api(request):
     atdb_hosts = ATDBProcessingSite.objects.values("name", "url")
     return render(request, "lofardata/api.html", {"atdb_hosts": atdb_hosts})
 
+def set_post_submit_values(specification, user):
+    specification.async_task_result = None
+    specification.is_ready = False
+    if specification.created_by is None:
+        specification.created_by = user
 
 class Specifications(ListView):
     serializer_class = WorkSpecificationSerializer
@@ -79,11 +86,18 @@ class Specifications(ListView):
         return queryset.filter(created_by=current_user.id).order_by("-created_on")
 
 
-class WorkSpecificationCreateUpdateView(UpdateView):
+class WorkSpecificationCreateUpdateView(LoginRequiredMixin, CanAccessWorkSpecificationMixin, UpdateView):
     template_name = "lofardata/workspecification/create_update.html"
     model = WorkSpecification
     form_class = WorkSpecificationForm
 
+    def get(self, request, *args, **kwargs):
+        specification = self.get_object()
+        if specification.is_editable():
+            return super().get(request, *args, **kwargs)
+        else:
+            return redirect('specification-detail', self.kwargs["pk"])
+
     def get_object(self, queryset=None):
         if self.kwargs.__len__() == 0 or self.kwargs["pk"] is None:
             specification = WorkSpecification()
@@ -113,8 +127,7 @@ class WorkSpecificationCreateUpdateView(UpdateView):
         action_ = form.data["action"]
         specification = form.instance
         if action_ == "Submit":
-            specification.async_task_result = None
-            specification.is_ready = False
+            set_post_submit_values(specification, self.request.user)
         if action_ == "Send":
             insert_task_into_atdb.delay(specification.pk)
         if action_ == "Successor":
@@ -134,7 +147,7 @@ class WorkSpecificationCreateUpdateView(UpdateView):
             return reverse_lazy("specification-update", kwargs={"pk": kwargs["pk"]})
 
 
-class WorkSpecificationDetailView(DetailView):
+class WorkSpecificationDetailView(LoginRequiredMixin, CanAccessWorkSpecificationMixin, DetailView):
     template_name = "lofardata/workspecification/detail.html"
     model = WorkSpecification
 
@@ -155,23 +168,23 @@ class WorkSpecificationDetailView(DetailView):
         return context
 
 
-class WorkSpecificationDeleteView(DeleteView):
+class WorkSpecificationDeleteView(LoginRequiredMixin, CanAccessWorkSpecificationMixin, DeleteView):
     template_name = "lofardata/workspecification/delete.html"
     model = WorkSpecification
     success_url = reverse_lazy("index")
 
 
-class WorkSpecificationInputsView(DetailView):
+class WorkSpecificationInputsView(LoginRequiredMixin, CanAccessWorkSpecificationMixin, DetailView):
     template_name = "lofardata/workspecification/inputs.html"
     model = WorkSpecification
 
 
-class WorkSpecificationATDBTasksView(DetailView):
+class WorkSpecificationATDBTasksView(LoginRequiredMixin, CanAccessWorkSpecificationMixin, DetailView):
     template_name = "lofardata/workspecification/tasks.html"
     model = WorkSpecification
 
 
-class WorkSpecificationDatasetSizeInfoView(DetailView):
+class WorkSpecificationDatasetSizeInfoView(LoginRequiredMixin, CanAccessWorkSpecificationMixin, DetailView):
     template_name = "lofardata/workspecification/dataset_size_info.html"
     model = WorkSpecification
 
@@ -192,14 +205,14 @@ class WorkSpecificationDatasetSizeInfoView(DetailView):
         return context
 
 
-class DataProductViewPerSasID(TemplateView):
+class DataProductViewPerSasID(LoginRequiredMixin, CanAccessWorkSpecificationMixin, TemplateView):
     template_name = "lofardata/workspecification/dataproducts.html"
 
     def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
 
         try:
-            specification = WorkSpecification.objects.get(pk=kwargs['pk'])
+            specification = self.get_object()
         except ObjectDoesNotExist:
             return context
 
@@ -208,6 +221,8 @@ class DataProductViewPerSasID(TemplateView):
         context["dataproduct_info"] = dataproductinfo.retrieve_combined_information(sas_id)
         return context
 
+    def get_object(self):
+        return WorkSpecification.objects.get(pk=self.kwargs['pk'])
 
 # ---------- REST API views ----------
 class DataProductView(generics.ListCreateAPIView):