diff --git a/compensation/account_urls.py b/compensation/account_urls.py
index 5daa6c87..511ee601 100644
--- a/compensation/account_urls.py
+++ b/compensation/account_urls.py
@@ -21,8 +21,9 @@ urlpatterns = [
     path('<id>/deadline/new', deadline_new_view, name="acc-new-deadline"),
 
     # Documents
-    # Document remove route can be found in konova/urls.py
     path('<id>/document/new/', new_document_view, name='acc-new-doc'),
+    path('document/<doc_id>', get_document_view, name='acc-get-doc'),
+    path('document/<doc_id>/remove/', remove_document_view, name='acc-remove-doc'),
 
     # Eco-account deductions
     path('<id>/remove/<deduction_id>', deduction_remove_view, name='deduction-remove'),
diff --git a/compensation/comp_urls.py b/compensation/comp_urls.py
index 1e79319b..84979d89 100644
--- a/compensation/comp_urls.py
+++ b/compensation/comp_urls.py
@@ -21,8 +21,9 @@ urlpatterns = [
     path('<id>/deadline/new', deadline_new_view, name="new-deadline"),
 
     # Documents
-    # Document remove route can be found in konova/urls.py
     path('<id>/document/new/', new_document_view, name='new-doc'),
+    path('document/<doc_id>', get_document_view, name='get-doc'),
+    path('document/<doc_id>/remove/', remove_document_view, name='remove-doc'),
 
     # Generic state routes
     path('state/<id>/remove', state_remove_view, name='state-remove'),
diff --git a/compensation/models.py b/compensation/models.py
index 556f1000..2732f9c7 100644
--- a/compensation/models.py
+++ b/compensation/models.py
@@ -5,16 +5,19 @@ Contact: michel.peltriaux@sgdnord.rlp.de
 Created on: 17.11.20
 
 """
+import shutil
+
 from django.contrib.auth.models import User
 from django.contrib.gis.db import models
 from django.core.validators import MinValueValidator
-from django.db.models import Sum
+from django.db.models import Sum, QuerySet
 from django.utils.translation import gettext_lazy as _
 
 from codelist.models import KonovaCode
 from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID
 from intervention.models import Intervention, ResponsibilityData
-from konova.models import BaseObject, BaseResource, Geometry, UuidModel
+from konova.models import BaseObject, BaseResource, Geometry, UuidModel, AbstractDocument, \
+    generate_document_file_upload_path
 from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE
 from user.models import UserActionLogEntry
 
@@ -137,7 +140,6 @@ class AbstractCompensation(BaseObject):
     deadlines = models.ManyToManyField("konova.Deadline", blank=True, related_name="+")
 
     geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL)
-    documents = models.ManyToManyField("konova.Document", blank=True)
 
     class Meta:
         abstract = True
@@ -197,6 +199,65 @@ class Compensation(AbstractCompensation):
             y,
         )
 
+    def get_documents(self) -> QuerySet:
+        """ Getter for all documents of a compensation
+
+        Returns:
+            docs (QuerySet): The queryset of all documents
+        """
+        docs = CompensationDocument.objects.filter(
+            instance=self
+        )
+        return docs
+
+
+class CompensationDocument(AbstractDocument):
+    """
+    Specializes document upload for revocations with certain path
+    """
+    instance = models.ForeignKey(
+        Compensation,
+        on_delete=models.CASCADE,
+        related_name="documents",
+    )
+    file = models.FileField(
+        upload_to=generate_document_file_upload_path,
+        max_length=1000,
+    )
+
+    def delete(self, *args, **kwargs):
+        """
+        Custom delete functionality for CompensationDocuments.
+        Removes the folder from the file system if there are no further documents for this entry.
+
+        Args:
+            *args ():
+            **kwargs ():
+
+        Returns:
+
+        """
+        comp_docs = self.instance.get_documents()
+
+        folder_path = None
+        if comp_docs.count() == 1:
+            # The only file left for this compensation is the one which is currently processed and will be deleted
+            # Make sure that the compensation folder itself is deleted as well, not only the file
+            # Therefore take the folder path from the file path
+            folder_path = self.file.path.split("/")[:-1]
+            folder_path = "/".join(folder_path)
+
+        # Remove the file itself
+        super().delete(*args, **kwargs)
+
+        # If a folder path has been set, we need to delete the whole folder!
+        if folder_path is not None:
+            try:
+                shutil.rmtree(folder_path)
+            except FileNotFoundError:
+                # Folder seems to be missing already...
+                pass
+
 
 class EcoAccount(AbstractCompensation):
     """
@@ -298,6 +359,65 @@ class EcoAccount(AbstractCompensation):
 
         return ret_msgs
 
+    def get_documents(self) -> QuerySet:
+        """ Getter for all documents of an EcoAccount
+
+        Returns:
+            docs (QuerySet): The queryset of all documents
+        """
+        docs = EcoAccountDocument.objects.filter(
+            instance=self
+        )
+        return docs
+
+
+class EcoAccountDocument(AbstractDocument):
+    """
+    Specializes document upload for revocations with certain path
+    """
+    instance = models.ForeignKey(
+        EcoAccount,
+        on_delete=models.CASCADE,
+        related_name="documents",
+    )
+    file = models.FileField(
+        upload_to=generate_document_file_upload_path,
+        max_length=1000,
+    )
+
+    def delete(self, *args, **kwargs):
+        """
+        Custom delete functionality for EcoAccountDocuments.
+        Removes the folder from the file system if there are no further documents for this entry.
+
+        Args:
+            *args ():
+            **kwargs ():
+
+        Returns:
+
+        """
+        acc_docs = self.instance.get_documents()
+
+        folder_path = None
+        if acc_docs.count() == 1:
+            # The only file left for this eco account is the one which is currently processed and will be deleted
+            # Make sure that the compensation folder itself is deleted as well, not only the file
+            # Therefore take the folder path from the file path
+            folder_path = self.file.path.split("/")[:-1]
+            folder_path = "/".join(folder_path)
+
+        # Remove the file itself
+        super().delete(*args, **kwargs)
+
+        # If a folder path has been set, we need to delete the whole folder!
+        if folder_path is not None:
+            try:
+                shutil.rmtree(folder_path)
+            except FileNotFoundError:
+                # Folder seems to be missing already...
+                pass
+
 
 class EcoAccountDeduction(BaseResource):
     """
diff --git a/compensation/templates/compensation/detail/compensation/includes/documents.html b/compensation/templates/compensation/detail/compensation/includes/documents.html
index 3801f7c8..3548e940 100644
--- a/compensation/templates/compensation/detail/compensation/includes/documents.html
+++ b/compensation/templates/compensation/detail/compensation/includes/documents.html
@@ -39,14 +39,14 @@
             {% for doc in obj.documents.all %}
             <tr>
                 <td class="align-middle">
-                    <a href="{% url 'doc-open' doc.id %}">
+                    <a href="{% url 'compensation:get-doc' doc.id %}">
                         {{ doc.title }}
                     </a>
                 </td>
                 <td class="align-middle">{{ doc.comment }}</td>
                 <td>
                     {% if is_default_member and has_access  %}
-                    <button data-form-url="{% url 'doc-remove' doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove document' %}">
+                    <button data-form-url="{% url 'compensation:remove-doc' doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove document' %}">
                         {% fa5_icon 'trash' %}
                     </button>
                     {% endif %}
diff --git a/compensation/templates/compensation/detail/eco_account/includes/documents.html b/compensation/templates/compensation/detail/eco_account/includes/documents.html
index 0c4b9ddd..bd371df2 100644
--- a/compensation/templates/compensation/detail/eco_account/includes/documents.html
+++ b/compensation/templates/compensation/detail/eco_account/includes/documents.html
@@ -39,14 +39,14 @@
             {% for doc in obj.documents.all %}
             <tr>
                 <td class="align-middle">
-                    <a href="{% url 'doc-open' doc.id %}">
+                    <a href="{% url 'compensation:acc-get-doc' doc.id %}">
                         {{ doc.title }}
                     </a>
                 </td>
                 <td class="align-middle">{{ doc.comment }}</td>
                 <td>
                     {% if is_default_member and has_access  %}
-                    <button data-form-url="{% url 'doc-remove' doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove document' %}">
+                    <button data-form-url="{% url 'compensation:acc-remove-doc' doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove document' %}">
                         {% fa5_icon 'trash' %}
                     </button>
                     {% endif %}
diff --git a/compensation/views/compensation_views.py b/compensation/views/compensation_views.py
index 0403af29..08091075 100644
--- a/compensation/views/compensation_views.py
+++ b/compensation/views/compensation_views.py
@@ -5,11 +5,12 @@ from django.shortcuts import render, get_object_or_404
 from django.utils.translation import gettext_lazy as _
 
 from compensation.forms import NewStateModalForm, NewDeadlineModalForm, NewActionModalForm
-from compensation.models import Compensation, CompensationState, CompensationAction
+from compensation.models import Compensation, CompensationState, CompensationAction, CompensationDocument
 from compensation.tables import CompensationTable
 from konova.contexts import BaseContext
 from konova.decorators import *
 from konova.forms import RemoveModalForm, SimpleGeomForm, NewDocumentForm
+from konova.utils.documents import get_document, remove_document
 from konova.utils.user_checks import in_group
 
 
@@ -163,6 +164,43 @@ def new_document_view(request: HttpRequest, id: str):
     )
 
 
+@login_required
+def get_document_view(request: HttpRequest, doc_id: str):
+    """ Returns the document as downloadable file
+
+    Wraps the generic document fetcher function from konova.utils.
+
+    Args:
+        request (HttpRequest): The incoming request
+        doc_id (str): The document id
+
+    Returns:
+
+    """
+    doc = get_object_or_404(CompensationDocument, id=doc_id)
+    return get_document(doc)
+
+
+@login_required
+def remove_document_view(request: HttpRequest, doc_id: str):
+    """ Removes the document from the database and file system
+
+    Wraps the generic functionality from konova.utils.
+
+    Args:
+        request (HttpRequest): The incoming request
+        doc_id (str): The document id
+
+    Returns:
+
+    """
+    doc = get_object_or_404(CompensationDocument, id=doc_id)
+    return remove_document(
+        request,
+        doc
+    )
+
+
 @login_required
 def state_new_view(request: HttpRequest, id: str):
     """ Renders a form for adding new states for a compensation
diff --git a/compensation/views/eco_account_views.py b/compensation/views/eco_account_views.py
index 86677ff5..c53f5349 100644
--- a/compensation/views/eco_account_views.py
+++ b/compensation/views/eco_account_views.py
@@ -14,13 +14,14 @@ from django.http import HttpRequest, Http404
 from django.shortcuts import render, get_object_or_404
 
 from compensation.forms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm
-from compensation.models import EcoAccount
+from compensation.models import EcoAccount, EcoAccountDocument
 from compensation.tables import EcoAccountTable
 from intervention.forms import NewDeductionForm
 from konova.contexts import BaseContext
 from konova.decorators import any_group_check, default_group_required, conservation_office_group_required
 from konova.forms import RemoveModalForm, SimpleGeomForm, NewDocumentForm, RecordModalForm
 from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
+from konova.utils.documents import get_document, remove_document
 from konova.utils.user_checks import in_group
 
 
@@ -289,6 +290,43 @@ def new_document_view(request: HttpRequest, id: str):
     )
 
 
+@login_required
+def get_document_view(request: HttpRequest, doc_id: str):
+    """ Returns the document as downloadable file
+
+    Wraps the generic document fetcher function from konova.utils.
+
+    Args:
+        request (HttpRequest): The incoming request
+        doc_id (str): The document id
+
+    Returns:
+
+    """
+    doc = get_object_or_404(EcoAccountDocument, id=doc_id)
+    return get_document(doc)
+
+
+@login_required
+def remove_document_view(request: HttpRequest, doc_id: str):
+    """ Removes the document from the database and file system
+
+    Wraps the generic functionality from konova.utils.
+
+    Args:
+        request (HttpRequest): The incoming request
+        doc_id (str): The document id
+
+    Returns:
+
+    """
+    doc = get_object_or_404(EcoAccountDocument, id=doc_id)
+    return remove_document(
+        request,
+        doc
+    )
+
+
 @login_required
 @default_group_required
 def new_deduction_view(request: HttpRequest, id: str):
diff --git a/ema/models.py b/ema/models.py
index aab3a86f..f777a813 100644
--- a/ema/models.py
+++ b/ema/models.py
@@ -1,8 +1,12 @@
+import shutil
+
 from django.contrib.auth.models import User
 from django.db import models
+from django.db.models import QuerySet
 
 from compensation.models import AbstractCompensation
-from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE
+from konova.models import AbstractDocument, generate_document_file_upload_path
+from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE, EMA_DOC_PATH
 from user.models import UserActionLogEntry
 
 
@@ -83,4 +87,63 @@ class Ema(AbstractCompensation):
 
         # ToDo: Add check methods!
 
-        return ret_msgs
\ No newline at end of file
+        return ret_msgs
+
+    def get_documents(self) -> QuerySet:
+        """ Getter for all documents of an EMA
+
+        Returns:
+            docs (QuerySet): The queryset of all documents
+        """
+        docs = EmaDocument.objects.filter(
+            instance=self
+        )
+        return docs
+
+
+class EmaDocument(AbstractDocument):
+    """
+    Specializes document upload for ema with certain path
+    """
+    instance = models.ForeignKey(
+        Ema,
+        on_delete=models.CASCADE,
+        related_name="documents",
+    )
+    file = models.FileField(
+        upload_to=generate_document_file_upload_path,
+        max_length=1000,
+    )
+
+    def delete(self, *args, **kwargs):
+        """
+        Custom delete functionality for EcoAccountDocuments.
+        Removes the folder from the file system if there are no further documents for this entry.
+
+        Args:
+            *args ():
+            **kwargs ():
+
+        Returns:
+
+        """
+        ema_docs = self.instance.get_documents()
+
+        folder_path = None
+        if ema_docs.count() == 1:
+            # The only file left for this EMA is the one which is currently processed and will be deleted
+            # Make sure that the compensation folder itself is deleted as well, not only the file
+            # Therefore take the folder path from the file path
+            folder_path = self.file.path.split("/")[:-1]
+            folder_path = "/".join(folder_path)
+
+        # Remove the file itself
+        super().delete(*args, **kwargs)
+
+        # If a folder path has been set, we need to delete the whole folder!
+        if folder_path is not None:
+            try:
+                shutil.rmtree(folder_path)
+            except FileNotFoundError:
+                # Folder seems to be missing already...
+                pass
diff --git a/ema/templates/ema/detail/includes/documents.html b/ema/templates/ema/detail/includes/documents.html
index 0670bbe7..96a24a67 100644
--- a/ema/templates/ema/detail/includes/documents.html
+++ b/ema/templates/ema/detail/includes/documents.html
@@ -39,14 +39,14 @@
             {% for doc in obj.documents.all %}
             <tr>
                 <td class="align-middle">
-                    <a href="{% url 'doc-open' doc.id %}">
+                    <a href="{% url 'ema:get-doc' doc.id %}">
                         {{ doc.title }}
                     </a>
                 </td>
                 <td class="align-middle">{{ doc.comment }}</td>
                 <td>
                     {% if is_default_member and has_access  %}
-                    <button data-form-url="{% url 'doc-remove' doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove document' %}">
+                    <button data-form-url="{% url 'ema:remove-doc' doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove document' %}">
                         {% fa5_icon 'trash' %}
                     </button>
                     {% endif %}
diff --git a/ema/urls.py b/ema/urls.py
index c3f5bd31..860d863b 100644
--- a/ema/urls.py
+++ b/ema/urls.py
@@ -24,6 +24,8 @@ urlpatterns = [
     # Documents
     # Document remove route can be found in konova/urls.py
     path('<id>/document/new/', document_new_view, name='new-doc'),
+    path('document/<doc_id>', get_document_view, name='get-doc'),
+    path('document/<doc_id>/remove/', remove_document_view, name='remove-doc'),
 
     # Generic state routes
     path('state/<id>/remove', state_remove_view, name='state-remove'),
diff --git a/ema/views.py b/ema/views.py
index df347deb..30520ca8 100644
--- a/ema/views.py
+++ b/ema/views.py
@@ -10,9 +10,10 @@ from compensation.forms import NewStateModalForm, NewActionModalForm, NewDeadlin
 from ema.tables import EmaTable
 from konova.contexts import BaseContext
 from konova.decorators import conservation_office_group_required
-from ema.models import Ema
+from ema.models import Ema, EmaDocument
 from konova.forms import RemoveModalForm, NewDocumentForm, SimpleGeomForm, RecordModalForm
 from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
+from konova.utils.documents import get_document, remove_document
 from konova.utils.user_checks import in_group
 
 
@@ -250,6 +251,43 @@ def document_new_view(request: HttpRequest, id: str):
     )
 
 
+@login_required
+def get_document_view(request: HttpRequest, doc_id: str):
+    """ Returns the document as downloadable file
+
+    Wraps the generic document fetcher function from konova.utils.
+
+    Args:
+        request (HttpRequest): The incoming request
+        doc_id (str): The document id
+
+    Returns:
+
+    """
+    doc = get_object_or_404(EmaDocument, id=doc_id)
+    return get_document(doc)
+
+
+@login_required
+def remove_document_view(request: HttpRequest, doc_id: str):
+    """ Removes the document from the database and file system
+
+    Wraps the generic functionality from konova.utils.
+
+    Args:
+        request (HttpRequest): The incoming request
+        doc_id (str): The document id
+
+    Returns:
+
+    """
+    doc = get_object_or_404(EmaDocument, id=doc_id)
+    return remove_document(
+        request,
+        doc
+    )
+
+
 @login_required
 def state_remove_view(request: HttpRequest, id: str):
     """ Renders a form for removing an EMA state
diff --git a/intervention/admin.py b/intervention/admin.py
index 2046935e..cf49bc39 100644
--- a/intervention/admin.py
+++ b/intervention/admin.py
@@ -1,6 +1,7 @@
 from django.contrib import admin
 
-from intervention.models import Intervention, ResponsibilityData, LegalData, Revocation
+from intervention.models import Intervention, ResponsibilityData, LegalData, Revocation, InterventionDocument
+from konova.admin import AbstractDocumentAdmin
 
 
 class InterventionAdmin(admin.ModelAdmin):
@@ -12,6 +13,8 @@ class InterventionAdmin(admin.ModelAdmin):
         "deleted",
     ]
 
+class InterventionDocumentAdmin(AbstractDocumentAdmin):
+    pass
 
 class ResponsibilityAdmin(admin.ModelAdmin):
     list_display = [
@@ -47,3 +50,4 @@ admin.site.register(Intervention, InterventionAdmin)
 admin.site.register(ResponsibilityData, ResponsibilityAdmin)
 admin.site.register(LegalData, LegalAdmin)
 admin.site.register(Revocation, RevocationAdmin)
+admin.site.register(InterventionDocument, InterventionDocumentAdmin)
diff --git a/intervention/forms.py b/intervention/forms.py
index 25ff7d36..508dbacb 100644
--- a/intervention/forms.py
+++ b/intervention/forms.py
@@ -15,9 +15,8 @@ from django.urls import reverse
 from django.utils.translation import gettext_lazy as _
 
 from compensation.models import EcoAccountDeduction, EcoAccount
-from intervention.models import Intervention, Revocation
+from intervention.models import Intervention, Revocation, RevocationDocument
 from konova.forms import BaseForm, BaseModalForm
-from konova.models import Document
 from konova.settings import DEFAULT_LAT, DEFAULT_LON, DEFAULT_ZOOM, ZB_GROUP, ETS_GROUP
 from konova.utils.messenger import Messenger
 from konova.utils.user_checks import in_group
@@ -372,19 +371,9 @@ class NewRevocationForm(BaseModalForm):
                 user=self.user,
                 action=UserAction.EDITED
             )
-            if self.cleaned_data["file"]:
-                document = Document.objects.create(
-                    title="revocation_of_{}".format(self.instance.identifier),
-                    date_of_creation=self.cleaned_data["date"],
-                    comment=self.cleaned_data["comment"],
-                    file=self.cleaned_data["file"],
-                )
-            else:
-                document = None
             revocation = Revocation.objects.create(
                 date=self.cleaned_data["date"],
                 comment=self.cleaned_data["comment"],
-                document=document,
                 created=created_action,
             )
             self.instance.modified = edited_action
@@ -392,6 +381,15 @@ class NewRevocationForm(BaseModalForm):
             self.instance.log.add(edited_action)
             self.instance.legal.revocation = revocation
             self.instance.legal.save()
+
+            if self.cleaned_data["file"]:
+                RevocationDocument.objects.create(
+                    title="revocation_of_{}".format(self.instance.identifier),
+                    date_of_creation=self.cleaned_data["date"],
+                    comment=self.cleaned_data["comment"],
+                    file=self.cleaned_data["file"],
+                    instance=revocation
+                )
         return revocation
 
 
diff --git a/intervention/models.py b/intervention/models.py
index a62da795..f4a7e739 100644
--- a/intervention/models.py
+++ b/intervention/models.py
@@ -5,19 +5,22 @@ Contact: michel.peltriaux@sgdnord.rlp.de
 Created on: 17.11.20
 
 """
+import shutil
+
 from django.contrib.auth.models import User
 from django.contrib.gis.db import models
+from django.db.models import QuerySet
 from django.utils.timezone import localtime
 from django.utils.translation import gettext_lazy as _
 
 from codelist.models import KonovaCode
 from codelist.settings import CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID, CODELIST_LAW_ID, \
     CODELIST_PROCESS_TYPE_ID
-from konova.models import BaseObject, Geometry, UuidModel, BaseResource
+from konova.models import BaseObject, Geometry, UuidModel, BaseResource, AbstractDocument, \
+    generate_document_file_upload_path
 from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE
 from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
 from konova.utils import generators
-from organisation.models import Organisation
 from user.models import UserActionLogEntry
 
 
@@ -68,15 +71,71 @@ class Revocation(BaseResource):
     """
     date = models.DateField(null=True, blank=True, help_text="Revocation from")
     comment = models.TextField(null=True, blank=True)
-    document = models.ForeignKey("konova.Document", blank=True, null=True, on_delete=models.SET_NULL)
 
-    def delete(self):
+    def delete(self, *args, **kwargs):
         # Make sure related objects are being removed as well
         if self.document:
-            self.document.delete()
+            self.document.delete(*args, **kwargs)
         super().delete()
 
 
+class RevocationDocument(AbstractDocument):
+    """
+    Specializes document upload for revocations with certain path
+    """
+    instance = models.OneToOneField(
+        Revocation,
+        on_delete=models.CASCADE,
+        related_name="document",
+    )
+    file = models.FileField(
+        upload_to=generate_document_file_upload_path,
+        max_length=1000,
+    )
+
+    @property
+    def intervention(self):
+        """
+        Shortcut for opening the related intervention
+
+        Returns:
+            intervention (Intervention)
+        """
+        return self.instance.legaldata.intervention
+
+    def delete(self, *args, **kwargs):
+        """
+        Custom delete functionality for RevocationDocuments.
+        Removes the folder from the file system if there are no further documents for this entry.
+
+        Args:
+            *args ():
+            **kwargs ():
+
+        Returns:
+
+        """
+        revoc_docs, other_intervention_docs = self.intervention.get_documents()
+
+        # Remove the file itself
+        super().delete(*args, **kwargs)
+
+        # Always remove 'revocation' folder
+        folder_path = self.file.path.split("/")
+        try:
+            shutil.rmtree("/".join(folder_path[:-1]))
+        except FileNotFoundError:
+            # Revocation subfolder seems to be missing already
+            pass
+
+        if other_intervention_docs.count() == 0:
+            # If there are no further documents for the intervention, we can simply remove the whole folder as well!
+            try:
+                shutil.rmtree("/".join(folder_path[:-2]))
+            except FileNotFoundError:
+                # Folder seems to be missing already
+                pass
+
 class LegalData(UuidModel):
     """
     Holds intervention legal data such as important dates, laws or responsible handler
@@ -112,7 +171,7 @@ class LegalData(UuidModel):
         }
     )
 
-    revocation = models.ForeignKey(Revocation, null=True, blank=True, help_text="Refers to 'Widerspruch am'", on_delete=models.SET_NULL)
+    revocation = models.OneToOneField(Revocation, null=True, blank=True, help_text="Refers to 'Widerspruch am'", on_delete=models.SET_NULL)
 
     def __str__(self):
         return "{} | {} | {}".format(
@@ -131,7 +190,6 @@ class Intervention(BaseObject):
         on_delete=models.SET_NULL,
         null=True,
         blank=True,
-        related_name='+',
         help_text="Holds data on responsible organizations ('Zulassungsbehörde', 'Eintragungsstelle')"
     )
     legal = models.OneToOneField(
@@ -139,11 +197,9 @@ class Intervention(BaseObject):
         on_delete=models.SET_NULL,
         null=True,
         blank=True,
-        related_name='+',
         help_text="Holds data on legal dates or law"
     )
     geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL)
-    documents = models.ManyToManyField("konova.Document", blank=True)
 
     # Checks - Refers to "Genehmigen" but optional
     checked = models.OneToOneField(
@@ -307,4 +363,67 @@ class Intervention(BaseObject):
             value = localtime(value)
             on = value.strftime(DEFAULT_DATE_TIME_FORMAT)
             tooltip = _("Recorded on {} by {}").format(on, self.recorded.user)
-        return tooltip
\ No newline at end of file
+        return tooltip
+
+    def get_documents(self) -> (QuerySet, QuerySet):
+        """ Getter for all documents of an intervention
+
+        Returns:
+            revoc_docs (QuerySet): The queryset of a revocation document
+            regular_docs (QuerySet): The queryset of regular other documents
+        """
+        revoc_docs = RevocationDocument.objects.filter(
+            instance=self.legal.revocation
+        )
+        regular_docs = InterventionDocument.objects.filter(
+            instance=self
+        )
+        return revoc_docs, regular_docs
+
+
+class InterventionDocument(AbstractDocument):
+    """
+    Specializes document upload for an intervention with certain path
+    """
+    instance = models.ForeignKey(
+        Intervention,
+        on_delete=models.CASCADE,
+        related_name="documents",
+    )
+    file = models.FileField(
+        upload_to=generate_document_file_upload_path,
+        max_length=1000,
+    )
+
+    def delete(self, *args, **kwargs):
+        """
+        Custom delete functionality for InterventionDocuments.
+        Removes the folder from the file system if there are no further documents for this entry.
+
+        Args:
+            *args ():
+            **kwargs ():
+
+        Returns:
+
+        """
+        revoc_docs, other_intervention_docs = self.instance.get_documents()
+
+        folder_path = None
+        if revoc_docs.count() == 0 and other_intervention_docs.count() == 1:
+            # The only file left for this intervention is the one which is currently processed and will be deleted
+            # Make sure that the intervention folder itself is deleted as well, not only the file
+            # Therefore take the folder path from the file path
+            folder_path = self.file.path.split("/")[:-1]
+            folder_path = "/".join(folder_path)
+
+        # Remove the file itself
+        super().delete(*args, **kwargs)
+
+        # If a folder path has been set, we need to delete the whole folder!
+        if folder_path is not None:
+            try:
+                shutil.rmtree(folder_path)
+            except FileNotFoundError:
+                # Folder seems to be missing already...
+                pass
diff --git a/intervention/templates/intervention/detail/includes/documents.html b/intervention/templates/intervention/detail/includes/documents.html
index c0bea2b0..54972bf5 100644
--- a/intervention/templates/intervention/detail/includes/documents.html
+++ b/intervention/templates/intervention/detail/includes/documents.html
@@ -39,14 +39,14 @@
             {% for doc in intervention.documents.all %}
             <tr>
                 <td class="align-middle">
-                    <a href="{% url 'doc-open' doc.id %}">
+                    <a href="{% url 'intervention:get-doc' doc.id %}">
                         {{ doc.title }}
                     </a>
                 </td>
                 <td class="align-middle">{{ doc.comment }}</td>
                 <td>
                     {% if is_default_member and has_access  %}
-                    <button data-form-url="{% url 'doc-remove' doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove document' %}">
+                    <button data-form-url="{% url 'intervention:remove-doc' doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove document' %}">
                         {% fa5_icon 'trash' %}
                     </button>
                     {% endif %}
diff --git a/intervention/templates/intervention/detail/includes/revocation.html b/intervention/templates/intervention/detail/includes/revocation.html
index 332b0d76..10a4c44e 100644
--- a/intervention/templates/intervention/detail/includes/revocation.html
+++ b/intervention/templates/intervention/detail/includes/revocation.html
@@ -31,10 +31,10 @@
                     {% trans 'From' context 'Revocation' %}
                 </th>
                 <th scope="col">
-                    {% trans 'Comment' %}
+                    {% trans 'Document' %}
                 </th>
                 <th scope="col">
-                    {% trans 'Document' %}
+                    {% trans 'Comment' %}
                 </th>
                 <th scope="col">
                     {% trans 'Action' %}
@@ -48,14 +48,14 @@
                 <td class="align-middle">
                     {{ rev.date }}
                 </td>
-                <td class="align-middle">{{ rev.comment }}</td>
                 <td class="align-middle">
                     {% if rev.document %}
-                        <a href="{% url 'doc-open' rev.document.id %}">
-                            {{ rev.document.file }}
+                        <a href="{% url 'intervention:get-doc-revocation' rev.document.id %}">
+                            {% trans 'Revocation' %}
                         </a>
                     {% endif %}
                 </td>
+                <td class="align-middle">{{ rev.comment }}</td>
                 <td>
                     {% if is_default_member and has_access  %}
                     <button data-form-url="{% url 'intervention:remove-revocation' rev.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove revocation' %}">
diff --git a/intervention/urls.py b/intervention/urls.py
index 2172e16b..51d1162f 100644
--- a/intervention/urls.py
+++ b/intervention/urls.py
@@ -9,13 +9,12 @@ from django.urls import path
 
 from intervention.views import index_view, new_view, open_view, edit_view, remove_view, new_document_view, share_view, \
     create_share_view, remove_revocation_view, new_revocation_view, run_check_view, log_view, new_deduction_view, \
-    record_view
+    record_view, remove_document_view, get_document_view, get_revocation_view
 
 app_name = "intervention"
 urlpatterns = [
     path("", index_view, name="index"),
     path('new/', new_view, name='new'),
-    path('<id>/document/new/', new_document_view, name='new-doc'),
     path('<id>', open_view, name='open'),
     path('<id>/log', log_view, name='log'),
     path('<id>/edit', edit_view, name='edit'),
@@ -25,10 +24,16 @@ urlpatterns = [
     path('<id>/check', run_check_view, name='run-check'),
     path('<id>/record', record_view, name='record'),
 
+    # Documents
+    path('<id>/document/new/', new_document_view, name='new-doc'),
+    path('document/<doc_id>', get_document_view, name='get-doc'),
+    path('document/<doc_id>/remove/', remove_document_view, name='remove-doc'),
+
     # Deductions
     path('<id>/deduction/new', new_deduction_view, name='acc-new-deduction'),
 
     # Revocation routes
     path('<id>/revocation/new', new_revocation_view, name='new-revocation'),
     path('revocation/<id>/remove', remove_revocation_view, name='remove-revocation'),
+    path('revocation/<doc_id>', get_revocation_view, name='get-doc-revocation'),
 ]
\ No newline at end of file
diff --git a/intervention/views.py b/intervention/views.py
index e8893cef..eb8cab4f 100644
--- a/intervention/views.py
+++ b/intervention/views.py
@@ -6,12 +6,13 @@ from django.shortcuts import render, get_object_or_404
 
 from intervention.forms import NewInterventionForm, EditInterventionForm, ShareInterventionForm, NewRevocationForm, \
     RunCheckForm, NewDeductionForm
-from intervention.models import Intervention, Revocation
+from intervention.models import Intervention, Revocation, InterventionDocument, RevocationDocument
 from intervention.tables import InterventionTable
 from konova.contexts import BaseContext
 from konova.decorators import *
 from konova.forms import SimpleGeomForm, NewDocumentForm, RemoveModalForm, RecordModalForm
 from konova.sub_settings.django_settings import DEFAULT_DATE_FORMAT
+from konova.utils.documents import remove_document, get_document
 from konova.utils.message_templates import FORM_INVALID, INTERVENTION_INVALID
 from konova.utils.user_checks import in_group
 
@@ -94,6 +95,60 @@ def new_document_view(request: HttpRequest, id: str):
     )
 
 
+@login_required
+def get_revocation_view(request: HttpRequest, doc_id: str):
+    """ Returns the revocation document as downloadable file
+
+    Wraps the generic document fetcher function from konova.utils.
+
+    Args:
+        request (HttpRequest): The incoming request
+        doc_id (str): The document id
+
+    Returns:
+
+    """
+    doc = get_object_or_404(RevocationDocument, id=doc_id)
+    return get_document(doc)
+
+
+@login_required
+def get_document_view(request: HttpRequest, doc_id: str):
+    """ Returns the document as downloadable file
+
+    Wraps the generic document fetcher function from konova.utils.
+
+    Args:
+        request (HttpRequest): The incoming request
+        doc_id (str): The document id
+
+    Returns:
+
+    """
+    doc = get_object_or_404(InterventionDocument, id=doc_id)
+    return get_document(doc)
+
+
+@login_required
+def remove_document_view(request: HttpRequest, doc_id: str):
+    """ Removes the document from the database and file system
+
+    Wraps the generic functionality from konova.utils.
+
+    Args:
+        request (HttpRequest): The incoming request
+        doc_id (str): The document id
+
+    Returns:
+
+    """
+    doc = get_object_or_404(InterventionDocument, id=doc_id)
+    return remove_document(
+        request,
+        doc
+    )
+
+
 @login_required
 @any_group_check
 def open_view(request: HttpRequest, id: str):
diff --git a/konova/admin.py b/konova/admin.py
index dc2c0583..c57117af 100644
--- a/konova/admin.py
+++ b/konova/admin.py
@@ -7,7 +7,7 @@ Created on: 22.07.21
 """
 from django.contrib import admin
 
-from konova.models import Geometry, Document, Deadline
+from konova.models import Geometry, Deadline
 
 
 class GeometryAdmin(admin.ModelAdmin):
@@ -17,7 +17,7 @@ class GeometryAdmin(admin.ModelAdmin):
     ]
 
 
-class DocumentAdmin(admin.ModelAdmin):
+class AbstractDocumentAdmin(admin.ModelAdmin):
     list_display = [
         "id",
         "title",
@@ -36,5 +36,4 @@ class DeadlineAdmin(admin.ModelAdmin):
 
 
 admin.site.register(Geometry, GeometryAdmin)
-admin.site.register(Document, DocumentAdmin)
 admin.site.register(Deadline, DeadlineAdmin)
diff --git a/konova/forms.py b/konova/forms.py
index 2ea9f57e..84f2a724 100644
--- a/konova/forms.py
+++ b/konova/forms.py
@@ -21,11 +21,11 @@ from django.shortcuts import render
 from django.utils import timezone
 from django.utils.translation import gettext_lazy as _
 
-from compensation.models import EcoAccount
-from ema.models import Ema
-from intervention.models import Intervention
+from compensation.models import EcoAccount, Compensation, EcoAccountDocument, CompensationDocument
+from ema.models import Ema, EmaDocument
+from intervention.models import Intervention, Revocation, RevocationDocument, InterventionDocument
 from konova.contexts import BaseContext
-from konova.models import Document, BaseObject
+from konova.models import BaseObject
 from konova.utils.message_templates import FORM_INVALID
 from user.models import UserActionLogEntry, UserAction
 
@@ -307,7 +307,7 @@ class NewDocumentForm(BaseModalForm):
             attrs={
                 "class": "w-75"
             }
-        )
+        ),
     )
     comment = forms.CharField(
         required=False,
@@ -322,6 +322,13 @@ class NewDocumentForm(BaseModalForm):
             }
         )
     )
+    document_instance_map = {
+        Intervention: InterventionDocument,
+        Compensation: CompensationDocument,
+        EcoAccount: EcoAccountDocument,
+        Revocation: RevocationDocument,
+        Ema: EmaDocument,
+    }
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
@@ -331,6 +338,12 @@ class NewDocumentForm(BaseModalForm):
         self.form_attrs = {
             "enctype": "multipart/form-data",  # important for file upload
         }
+        self.document_type = self.document_instance_map.get(
+            self.instance.__class__,
+            None
+        )
+        if not self.document_type:
+            raise NotImplementedError("Unsupported document type for {}".format(self.instance.__class__))
 
     def save(self):
         with transaction.atomic():
@@ -338,14 +351,14 @@ class NewDocumentForm(BaseModalForm):
                 user=self.user,
                 action=UserAction.CREATED,
             )
-            doc = Document.objects.create(
+            doc = self.document_type.objects.create(
                 created=action,
                 title=self.cleaned_data["title"],
                 comment=self.cleaned_data["comment"],
                 file=self.cleaned_data["file"],
                 date_of_creation=self.cleaned_data["creation_date"],
+                instance=self.instance,
             )
-            self.instance.documents.add(doc)
 
             edited_action = UserActionLogEntry.objects.create(
                 user=self.user,
diff --git a/konova/models.py b/konova/models.py
index 2c554f64..492dcef7 100644
--- a/konova/models.py
+++ b/konova/models.py
@@ -18,6 +18,7 @@ from compensation.settings import COMPENSATION_IDENTIFIER_TEMPLATE, COMPENSATION
     ECO_ACCOUNT_IDENTIFIER_TEMPLATE, ECO_ACCOUNT_IDENTIFIER_LENGTH
 from ema.settings import EMA_ACCOUNT_IDENTIFIER_LENGTH, EMA_ACCOUNT_IDENTIFIER_TEMPLATE
 from intervention.settings import INTERVENTION_IDENTIFIER_LENGTH, INTERVENTION_IDENTIFIER_TEMPLATE
+from konova.settings import INTERVENTION_REVOCATION_DOC_PATH
 from konova.utils.generators import generate_random_string
 from user.models import UserActionLogEntry, UserAction
 
@@ -220,7 +221,47 @@ class Deadline(BaseResource):
         return None
 
 
-class Document(BaseResource):
+def generate_document_file_upload_path(instance, filename):
+    """ Generates the file upload path for certain document instances
+
+    Documents derived from AbstractDocument need specific upload paths for their related models.
+
+    Args:
+        instance (): The document instance
+        filename (): The filename
+
+    Returns:
+
+    """
+    from compensation.models import CompensationDocument, EcoAccountDocument
+    from ema.models import EmaDocument
+    from intervention.models import InterventionDocument, RevocationDocument
+    from konova.settings import ECO_ACCOUNT_DOC_PATH, EMA_DOC_PATH, \
+        COMPENSATION_DOC_PATH, \
+        INTERVENTION_DOC_PATH
+
+    # Map document types to paths on the hard drive
+    path_map = {
+        InterventionDocument: INTERVENTION_DOC_PATH,
+        CompensationDocument: COMPENSATION_DOC_PATH,
+        EmaDocument: EMA_DOC_PATH,
+        RevocationDocument: INTERVENTION_REVOCATION_DOC_PATH,
+        EcoAccountDocument: ECO_ACCOUNT_DOC_PATH,
+    }
+    path = path_map.get(instance.__class__, None)
+    if path is None:
+        raise NotImplementedError("Unidentified document type: {}".format(instance.__class__))
+
+    # RevocationDocument needs special treatment, since these files need to be stored in a subfolder of the related
+    # instance's (Revocation) legaldata interventions folder
+    if instance.__class__ is RevocationDocument:
+        path = path.format(instance.intervention.id)
+    else:
+        path = path.format(instance.instance.id)
+    return path + filename
+
+
+class AbstractDocument(BaseResource):
     """
     Documents can be attached to compensation or intervention for uploading legal documents or pictures.
     """
@@ -229,6 +270,9 @@ class Document(BaseResource):
     file = models.FileField()
     comment = models.TextField()
 
+    class Meta:
+        abstract = True
+
     def delete(self, using=None, keep_parents=False):
         """ Custom delete function to remove the real file from the hard drive
 
@@ -239,7 +283,11 @@ class Document(BaseResource):
         Returns:
 
         """
-        os.remove(self.file.file.name)
+        try:
+            os.remove(self.file.file.name)
+        except FileNotFoundError:
+            # File seems to missing anyway - continue!
+            pass
         super().delete(using=using, keep_parents=keep_parents)
 
 
diff --git a/konova/settings.py b/konova/settings.py
index e6c37d6f..aa028000 100644
--- a/konova/settings.py
+++ b/konova/settings.py
@@ -55,7 +55,20 @@ DEFAULT_GROUP = "Default"
 ZB_GROUP = "Registration office"
 ETS_GROUP = "Conservation office"
 
-
 # Needed to redirect to LANIS
 ## Values to be inserted are [zoom_level, x_coord, y_coord]
 LANIS_LINK_TEMPLATE = "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/index.php?lang=de&zl={}&x={}&y={}&bl=tk_rlp_tms_grau&bo=1&lo=0.8,0.8,0.8,0.6,0.8,0.8,0.8,0.8,0.8&layers=eiv_f,eiv_l,eiv_p,kom_f,kom_l,kom_p,oek_f,ema_f,mae&service=kartendienste_naturschutz"
+
+# ALLOWED FILE UPLOAD DEFINITIONS
+# Default: Upload into upper project folder
+MEDIA_ROOT = BASE_DIR + "/.."
+
+# DOCUMENT UPLOAD PATHS
+# Extends MEDIA_ROOT
+## {} is a placeholder for the object's uuid --> each object will have it's own folder
+BASE_DOC_PATH = "konova_uploaded_files/"
+INTERVENTION_DOC_PATH = BASE_DOC_PATH + "interventions/{}/"
+INTERVENTION_REVOCATION_DOC_PATH = BASE_DOC_PATH + "interventions/{}/revocation/"
+COMPENSATION_DOC_PATH = BASE_DOC_PATH + "compensations/{}/"
+ECO_ACCOUNT_DOC_PATH = BASE_DOC_PATH + "eco_account/{}/"
+EMA_DOC_PATH = BASE_DOC_PATH + "ema/{}/"
\ No newline at end of file
diff --git a/konova/urls.py b/konova/urls.py
index 32173a85..37909256 100644
--- a/konova/urls.py
+++ b/konova/urls.py
@@ -22,7 +22,7 @@ from konova.autocompletes import OrganisationAutocomplete, NonOfficialOrganisati
     RegistrationOfficeCodeAutocomplete, ConservationOfficeCodeAutocomplete
 from konova.settings import SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY, DEBUG
 from konova.sso.sso import KonovaSSOClient
-from konova.views import logout_view, home_view, get_document_view, remove_document_view, remove_deadline_view
+from konova.views import logout_view, home_view, remove_deadline_view
 
 sso_client = KonovaSSOClient(SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY)
 urlpatterns = [
@@ -38,10 +38,6 @@ urlpatterns = [
     path('news/', include("news.urls")),
     path('news/', include("codelist.urls")),
 
-    # Generic documents routes
-    path('document/<id>', get_document_view, name="doc-open"),
-    path('document/<id>/remove', remove_document_view, name="doc-remove"),
-
     # Generic deadline routes
     path('deadline/<id>/remove', remove_deadline_view, name="deadline-remove"),
 
diff --git a/konova/utils/documents.py b/konova/utils/documents.py
new file mode 100644
index 00000000..695347c3
--- /dev/null
+++ b/konova/utils/documents.py
@@ -0,0 +1,53 @@
+"""
+Author: Michel Peltriaux
+Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
+Contact: michel.peltriaux@sgdnord.rlp.de
+Created on: 01.09.21
+
+"""
+from django.http import FileResponse, HttpRequest, HttpResponse, Http404
+from django.utils.translation import gettext_lazy as _
+
+from konova.forms import RemoveModalForm
+from konova.models import AbstractDocument
+
+
+def get_document(doc: AbstractDocument):
+    """ Returns a document as downloadable attachment
+
+    Args:
+        request (HttpRequest): The incoming request
+        id (str): The document id
+
+    Returns:
+
+    """
+    try:
+        return FileResponse(doc.file, as_attachment=True)
+    except FileNotFoundError:
+        raise Http404()
+
+
+def remove_document(request: HttpRequest, doc: AbstractDocument):
+    """ Renders a form for uploading new documents
+
+    This function works using a modal. We are not using the regular way, the django bootstrap modal forms are
+    intended to be used. Instead of View classes we work using the classic way of dealing with forms (see below).
+    It is important to mention, that modal forms, which should reload the page afterwards, must provide a
+    'reload_page' bool in the context. This way, the modal may reload the page or not.
+
+    For further details see the comments in templates/modal or
+    https://github.com/trco/django-bootstrap-modal-forms
+
+    Args:
+        request (HttpRequest): The incoming request
+
+    Returns:
+
+    """
+    title = doc.title
+    form = RemoveModalForm(request.POST or None, instance=doc, user=request.user)
+    return form.process_request(
+        request=request,
+        msg_success=_("Document '{}' deleted").format(title)
+    )
\ No newline at end of file
diff --git a/konova/views.py b/konova/views.py
index cfe1b3c8..e1ca2db6 100644
--- a/konova/views.py
+++ b/konova/views.py
@@ -17,7 +17,7 @@ from intervention.models import Intervention
 from konova.contexts import BaseContext
 from konova.decorators import any_group_check
 from konova.forms import RemoveModalForm
-from konova.models import Document, Deadline
+from konova.models import Deadline
 from news.models import ServerMessage
 from konova.settings import SSO_SERVER_BASE
 
@@ -97,48 +97,6 @@ def home_view(request: HttpRequest):
     return render(request, template, context)
 
 
-@login_required
-def get_document_view(request: HttpRequest, id: str):
-    """ Returns a document as downloadable attachment
-
-    Args:
-        request (HttpRequest): The incoming request
-        id (str): The document id
-
-    Returns:
-
-    """
-    doc = get_object_or_404(Document, id=id)
-    return FileResponse(doc.file, as_attachment=True)
-
-
-@login_required
-def remove_document_view(request: HttpRequest, id: str):
-    """ Renders a form for uploading new documents
-
-    This function works using a modal. We are not using the regular way, the django bootstrap modal forms are
-    intended to be used. Instead of View classes we work using the classic way of dealing with forms (see below).
-    It is important to mention, that modal forms, which should reload the page afterwards, must provide a
-    'reload_page' bool in the context. This way, the modal may reload the page or not.
-
-    For further details see the comments in templates/modal or
-    https://github.com/trco/django-bootstrap-modal-forms
-
-    Args:
-        request (HttpRequest): The incoming request
-
-    Returns:
-
-    """
-    doc = get_object_or_404(Document, id=id)
-    title = doc.title
-    form = RemoveModalForm(request.POST or None, instance=doc, user=request.user)
-    return form.process_request(
-        request=request,
-        msg_success=_("Document '{}' deleted").format(title)
-    )
-
-
 @login_required
 def remove_deadline_view(request: HttpRequest, id:str):
     """ Renders a modal form for removing a deadline object