diff --git a/README.md b/README.md
index 6173d8b887407fa8e7d36644138fbe1fac0ee3e5..715d73f69dd606c9318e82c2acfbbbc3709cc16b 100644
--- a/README.md
+++ b/README.md
@@ -177,7 +177,6 @@ You may want to also uninstall `django-nose`, as it is an optional test runner t
 
 We use [rq](https://python-rq.org/), integrated via [django-rq](https://pypi.org/project/django-rq/), to run tasks without blocking an API request or causing timeouts. To call them in Python code, you should use the trigger methods in `arkindex.project.triggers`; those will do some safety checks to make catching some errors easier in dev. The actual tasks are in `arkindex.documents.tasks`. The following tasks exist:
 
-* Delete ML results from a corpus or an element and its children: `ml_results_delete`
 * Delete a corpus: `corpus_delete`
 * Reindex elements, transcriptions or entities into ElasticSearch: `reindex_start`
 
diff --git a/arkindex/dataimport/tests/test_process_elements.py b/arkindex/dataimport/tests/test_process_elements.py
index c0bc419ebe8cb06a4a0ed510643be142f394bc7c..bfc367349c9781bf37e768989faf0efc85ff1519 100644
--- a/arkindex/dataimport/tests/test_process_elements.py
+++ b/arkindex/dataimport/tests/test_process_elements.py
@@ -3,8 +3,8 @@ import uuid
 from django.urls import reverse
 from rest_framework import status
 
-from arkindex.dataimport.models import DataImport, DataImportMode
-from arkindex.documents.models import Classification, ClassificationState, Corpus, DataSource, Element, MLClass
+from arkindex.dataimport.models import DataImport, DataImportMode, WorkerVersion
+from arkindex.documents.models import Classification, ClassificationState, Corpus, Element, MLClass
 from arkindex.project.tests import FixtureAPITestCase
 
 
@@ -127,44 +127,44 @@ class TestProcessElements(FixtureAPITestCase):
         cls.line_5.add_parent(cls.page_5)
 
         # Create best classes
-        source = DataSource.objects.first()
-        cls.coffee_source = MLClass.objects.create(name='C0FFEE', corpus=cls.private_corpus)
-        cls.food_source = MLClass.objects.create(name='F00D', corpus=cls.private_corpus)
+        worker_version = WorkerVersion.objects.get(worker__slug='reco')
+        cls.coffee_class = MLClass.objects.create(name='C0FFEE', corpus=cls.private_corpus)
+        cls.food_class = MLClass.objects.create(name='F00D', corpus=cls.private_corpus)
         Classification.objects.create(
             element=cls.folder_2,
             state=ClassificationState.Validated,
-            ml_class=cls.food_source,
-            source=source
+            ml_class=cls.food_class,
+            worker_version=worker_version,
         )
         Classification.objects.create(
             element=cls.page_1,
             state=ClassificationState.Validated,
-            ml_class=cls.coffee_source,
-            source=source
+            ml_class=cls.coffee_class,
+            worker_version=worker_version,
         )
         Classification.objects.create(
             element=cls.page_2,
             high_confidence=True,
-            ml_class=cls.food_source,
-            source=source
+            ml_class=cls.food_class,
+            worker_version=worker_version,
         )
         Classification.objects.create(
             element=cls.page_3,
             state=ClassificationState.Validated,
-            ml_class=cls.food_source,
-            source=source
+            ml_class=cls.food_class,
+            worker_version=worker_version,
         )
         Classification.objects.create(
             element=cls.page_5,
             high_confidence=True,
-            ml_class=cls.food_source,
-            source=source
+            ml_class=cls.food_class,
+            worker_version=worker_version,
         )
         Classification.objects.create(
             element=cls.page_5,
             state=ClassificationState.Validated,
-            ml_class=cls.coffee_source ,
-            source=source
+            ml_class=cls.coffee_class,
+            worker_version=worker_version,
         )
 
     def setUp(self):
@@ -323,7 +323,7 @@ class TestProcessElements(FixtureAPITestCase):
         ])
 
     def test_filter_best_class_by_id(self):
-        self.dataimport.best_class = self.food_source.id
+        self.dataimport.best_class = self.food_class.id
         self.dataimport.save()
         elements = [self.page_5, self.page_3, self.folder_2, self.page_2]
 
@@ -472,7 +472,7 @@ class TestProcessElements(FixtureAPITestCase):
         ])
 
     def test_load_children_and_filter_best_class_by_id(self):
-        self.dataimport.best_class = self.food_source.id
+        self.dataimport.best_class = self.food_class.id
         self.dataimport.load_children = True
         self.dataimport.save()
         elements = [self.folder_2, self.page_2, self.page_3, self.page_5]
diff --git a/arkindex/documents/admin.py b/arkindex/documents/admin.py
index 3286682ba9ecfa7721b87acb7872d58bf81ea021..d4aa5ebdf074e374b760f0f1fc5d14881dae5d89 100644
--- a/arkindex/documents/admin.py
+++ b/arkindex/documents/admin.py
@@ -7,7 +7,6 @@ from arkindex.documents.models import (
     AllowedMetaData,
     Classification,
     Corpus,
-    DataSource,
     Element,
     ElementType,
     Entity,
@@ -34,12 +33,6 @@ class CorpusAdmin(admin.ModelAdmin):
         return False
 
 
-class DataSourceAdmin(admin.ModelAdmin):
-    list_display = ('id', 'type', 'slug', 'revision', 'internal')
-    list_filter = [('type', EnumFieldListFilter), 'internal']
-    readonly_fields = ('id', )
-
-
 class ClassificationInline(admin.TabularInline):
     model = Classification
     readonly_fields = ('confidence', 'high_confidence', )
@@ -85,8 +78,7 @@ class ElementAdmin(admin.ModelAdmin):
 
 class TranscriptionAdmin(admin.ModelAdmin):
     list_display = ('id', 'text', 'score', 'element', )
-    list_filter = ['source']
-    fields = ('id', 'text', 'score', 'element', 'source', )
+    fields = ('id', 'text', 'score', 'element', )
     readonly_fields = ('id', )
     raw_id_fields = ('element', )
 
@@ -125,7 +117,6 @@ class EntityRoleAdmin(admin.ModelAdmin):
 
 
 admin.site.register(Corpus, CorpusAdmin)
-admin.site.register(DataSource, DataSourceAdmin)
 admin.site.register(Element, ElementAdmin)
 admin.site.register(Transcription, TranscriptionAdmin)
 admin.site.register(MLClass, MLClassAdmin)
diff --git a/arkindex/documents/api/elements.py b/arkindex/documents/api/elements.py
index 3b9393d5d7a109f68658d214161394219fc10ab5..256189e5ff46497f2dd95313de3d0b84ee0200f1 100644
--- a/arkindex/documents/api/elements.py
+++ b/arkindex/documents/api/elements.py
@@ -58,7 +58,7 @@ from arkindex.project.permissions import IsAuthenticated, IsVerified, IsVerified
 from arkindex.project.tools import BulkMap
 from arkindex.project.triggers import corpus_delete, element_trash
 
-classifications_queryset = Classification.objects.select_related('ml_class', 'source').order_by('-confidence')
+classifications_queryset = Classification.objects.select_related('ml_class', 'worker_version').order_by('-confidence')
 
 best_classifications_prefetch = Prefetch(
     'classifications',
@@ -867,8 +867,9 @@ class ElementTranscriptions(ListAPIView):
         self.check_object_permissions(self.request, element)
 
         # ORDER BY casting IDs as char to avoid the PostgreSQL optimizer's inefficient scan
+        # TODO: See if select_related is faster than a prefetch on this endpoint
         queryset = Transcription.objects \
-            .prefetch_related('element__zone__image__server', 'source') \
+            .prefetch_related('element__zone__image__server', 'worker_version') \
             .annotate(char_id=Cast('id', output_field=CharField())) \
             .order_by('char_id')
 
diff --git a/arkindex/documents/api/ml.py b/arkindex/documents/api/ml.py
index bd46eb8a71873e554c5e55b1e50e49dca0977c84..ce49c4f205493ad80d9af536a457fbdecac5b705 100644
--- a/arkindex/documents/api/ml.py
+++ b/arkindex/documents/api/ml.py
@@ -11,7 +11,6 @@ from rest_framework.generics import (
     GenericAPIView,
     ListAPIView,
     ListCreateAPIView,
-    RetrieveDestroyAPIView,
     RetrieveUpdateDestroyAPIView,
 )
 from rest_framework.response import Response
@@ -20,10 +19,8 @@ from arkindex.documents.models import (
     Classification,
     ClassificationState,
     Corpus,
-    DataSource,
     Element,
     ElementPath,
-    Entity,
     MLClass,
     Right,
     Transcription,
@@ -36,7 +33,6 @@ from arkindex.documents.serializers.ml import (
     ClassificationsSelectionSerializer,
     ClassificationsSerializer,
     CountMLClassSerializer,
-    DataSourceStatsSerializer,
     ElementTranscriptionsBulkSerializer,
     TranscriptionBulkSerializer,
     TranscriptionCreateSerializer,
@@ -45,9 +41,8 @@ from arkindex.documents.serializers.ml import (
 from arkindex.images.models import Zone
 from arkindex.project.filters import SafeSearchFilter
 from arkindex.project.mixins import CorpusACLMixin, DeprecatedMixin, SelectionMixin
-from arkindex.project.permissions import IsAdminUser, IsVerified, IsVerifiedOrReadOnly
-from arkindex.project.triggers import ml_results_delete, reindex_start
-from arkindex_common.ml_tool import MLToolType
+from arkindex.project.permissions import IsVerified, IsVerifiedOrReadOnly
+from arkindex.project.triggers import reindex_start
 
 logger = logging.getLogger(__name__)
 
@@ -134,10 +129,9 @@ class TranscriptionEdit(RetrieveUpdateDestroyAPIView):
         rights = transcription.element.corpus.get_acl_rights(request.user)
 
         errors = defaultdict(list)
-        non_manual_transcription = bool(transcription.worker_version or transcription.source and transcription.source.slug != 'manual')
         if Right.Write not in rights:
             errors['__all__'].append('A write access to transcription element corpus is required.')
-        if Right.Admin not in rights and non_manual_transcription:
+        if Right.Admin not in rights and transcription.worker_version_id:
             errors['__all__'].append('Only admins can edit non-manual transcription.')
         if (errors):
             raise PermissionDenied(errors)
@@ -460,20 +454,12 @@ class ManageClassificationsSelection(SelectionMixin, CorpusACLMixin, CreateAPIVi
 
     def create(self, corpus, request, *args, **kwargs):
         ml_class = MLClass.objects.filter(id=request.data['ml_class']).first()
-        data_source, _ = DataSource.objects.get_or_create(
-            type=MLToolType.Classifier,
-            slug='manual',
-            defaults={
-                'revision': '',
-                'internal': False,
-            }
-        )
 
         elements = self.get_selection(corpus.id)
         existing_element_ids = set(Classification.objects.filter(
             element_id__in=elements,
-            source_id=data_source.id,
-            ml_class_id=ml_class.id
+            ml_class_id=ml_class.id,
+            worker_version_id=None,
         ).values_list('element_id', flat=True))
 
         classifications = []
@@ -481,7 +467,6 @@ class ManageClassificationsSelection(SelectionMixin, CorpusACLMixin, CreateAPIVi
             classifications.append(Classification(
                 element=element,
                 ml_class=ml_class,
-                source=data_source,
                 moderator=self.request.user,
                 state=ClassificationState.Validated,
                 high_confidence=False,
@@ -535,11 +520,7 @@ class ClassificationReject(ClassificationModerationActionsMixin):
     def put(self, request, *args, **kwargs):
         instance = self.get_object()
 
-        manual = (
-            instance.source and instance.source.slug == 'manual'
-            or not instance.source and not instance.worker_version
-        )
-        if manual:
+        if not instance.worker_version_id:
             # Delete manual classifications upon rejection
             instance.delete()
             return Response(None, status=status.HTTP_204_NO_CONTENT)
@@ -549,110 +530,3 @@ class ClassificationReject(ClassificationModerationActionsMixin):
         instance.save(update_fields=['moderator', 'state'])
         serializer = self.get_serializer(instance)
         return Response(serializer.data, status=status.HTTP_200_OK)
-
-
-class MLStatsBase(object):
-    serializer_class = DataSourceStatsSerializer
-    permission_classes = (IsAdminUser, )
-    # Make DRF understand we return an unpaginated list, for OpenAPI schema generation
-    action = 'list'
-    pagination_class = None
-
-    def get_count_querysets(self, instance):
-        """
-        Given an object returned by Django REST Framework's get_object,
-        should return a dict mapping attribute names to querysets
-        """
-        if isinstance(instance, Element):
-            if not instance.type.folder:
-                return {
-                    'transcriptions_count': Transcription.objects.filter(element_id=instance.id),
-                    'entities_count': Entity.objects.filter(
-                        Q(transcriptions__element_id=instance.id)
-                        | Q(metadatas__element_id=instance.id)
-                    ),
-                    'classifications_count': Classification.objects.filter(element_id=instance.id),
-                }
-            # The folder AND its children
-            elements = Element.objects.filter(id=instance.id).values('id').union(
-                # Disable ordering here because we do not need it and it adds an extra column,
-                # causing the UNION to fail
-                Element.objects.get_descending(instance.id).order_by().values('id')
-            )
-        elif isinstance(instance, Corpus):
-            elements = instance.elements.all()
-        else:
-            raise ValueError('Instance is not a corpus or an element: {}'.format(instance))
-
-        return {
-            'transcriptions_count': Transcription.objects.filter(element__in=elements),
-            'entities_count': Entity.objects.filter(
-                Q(transcriptions__element__in=elements)
-                | Q(metadatas__element__in=elements)
-            ),
-            'classifications_count': Classification.objects.filter(element__in=elements),
-        }
-
-    def get_counts(self):
-        count_querysets = self.get_count_querysets(self.get_object())
-
-        # A dict that links source IDs to another dict holding their stats:
-        # {id: {transcriptions_count: 42, …}, …}
-        counts = defaultdict(dict)
-
-        # Request statistics for each kind of ML result, grouped by source ID: lowers the need for any joins or unions
-        for field_name, queryset in count_querysets.items():
-            queryset = queryset.values('source_id').annotate(count=Count('id')).values_list('source_id', 'count')
-            for source_id, count in queryset:
-                counts[source_id][field_name] = count
-
-        # Fetch the source IDs returned by the previous queries,
-        # and set the counts as if they were usual queryset annotations.
-        sources = list(DataSource.objects.filter(id__in=counts.keys()).order_by('name'))
-        for source in sources:
-            for name, value in counts[source.id].items():
-                setattr(source, name, value)
-
-        return sources
-
-    def get_serializer(self, *args, **kwargs):
-        # Force the serializer to work as a list, except when get_serializer is called without arguments
-        # because the OpenAPI schema generator needs a normal serializer
-        if args or kwargs:
-            kwargs['many'] = True
-        return super().get_serializer(*args, **kwargs)
-
-    def retrieve(self, *args, **kwargs):
-        serializer = self.get_serializer(self.get_counts())
-        return Response(serializer.data)
-
-
-class ElementMLStats(MLStatsBase, RetrieveDestroyAPIView):
-    openapi_overrides = {
-        'operationId': 'RetrieveElementMLStats',
-        'description': 'List machine learning result sources along with their result counts for an element',
-        'tags': ['ml'],
-    }
-
-    def get_queryset(self):
-        return Element.objects.filter(corpus__in=Corpus.objects.readable(self.request.user)).select_related('type')
-
-    def destroy(self, *args, **kwargs):
-        ml_results_delete(element=self.get_object(), user_id=self.request.user.id)
-        return Response(status=status.HTTP_204_NO_CONTENT)
-
-
-class CorpusMLStats(MLStatsBase, RetrieveDestroyAPIView):
-    openapi_overrides = {
-        'operationId': 'RetrieveCorpusMLStats',
-        'description': 'List machine learning results sources along with their result counts '
-                       'for all elements in a corpus',
-        'tags': ['ml'],
-    }
-
-    def get_queryset(self):
-        return Corpus.objects.readable(self.request.user).only('id')
-
-    def destroy(self, *args, **kwargs):
-        ml_results_delete(corpus=self.get_object(), user_id=self.request.user.id)
-        return Response(status=status.HTTP_204_NO_CONTENT)
diff --git a/arkindex/documents/api/search.py b/arkindex/documents/api/search.py
index 756f020c0c39ea042bf33573a7d2bd31ee350e5b..eeda0732222250e09a7c28d8392e3d31694576f1 100644
--- a/arkindex/documents/api/search.py
+++ b/arkindex/documents/api/search.py
@@ -25,7 +25,7 @@ class ElementSearch(SearchAPIView):
         'operationId': 'SearchElements',
         'security': [],
         'description': 'Get a list of elements with their parents, the total number of transcriptions '
-                       'in each element, and a few (not all) of their transcriptions, with their source, '
+                       'in each element, and a few (not all) of their transcriptions, with their worker version, '
                        'type, zone and image, for a given query.',
         'tags': ['search'],
     }
diff --git a/arkindex/documents/fixtures/data.json b/arkindex/documents/fixtures/data.json
index 1fa8f84e0d7de2cfa2b6fe90972667e376971297..d89d86f3f7d62c47037682231ef96c2c6c54dfd2 100644
--- a/arkindex/documents/fixtures/data.json
+++ b/arkindex/documents/fixtures/data.json
@@ -1,115 +1,115 @@
 [
 {
     "model": "dataimport.repository",
-    "pk": "32416126-e127-4b7a-8042-ad9a47eb9d78",
+    "pk": "0d67c9eb-f386-45b5-8de0-1e319ddbdbe9",
     "fields": {
-        "url": "http://gitlab/repo",
-        "type": "iiif",
-        "hook_token": "hook-token",
-        "credentials": "e0910bb1-91f7-4672-a51f-888ad5173fdd",
+        "url": "http://my_repo.fake/workers/worker",
+        "type": "worker",
+        "hook_token": "worker-hook-token",
+        "credentials": "f0fc6a6d-288b-40bb-9f3c-d90843627f01",
         "provider_name": "GitLabProvider"
     }
 },
 {
     "model": "dataimport.repository",
-    "pk": "4730656e-3cda-4bd7-b6f8-73f8aec667c4",
+    "pk": "6be4a57c-bef9-47ed-a13f-12a7bc9e4363",
     "fields": {
-        "url": "http://my_repo.fake/workers/worker",
-        "type": "worker",
-        "hook_token": "worker-hook-token",
-        "credentials": "e0910bb1-91f7-4672-a51f-888ad5173fdd",
+        "url": "http://gitlab/repo",
+        "type": "iiif",
+        "hook_token": "hook-token",
+        "credentials": "f0fc6a6d-288b-40bb-9f3c-d90843627f01",
         "provider_name": "GitLabProvider"
     }
 },
 {
     "model": "dataimport.revision",
-    "pk": "a71737e4-3b10-4c2f-92ba-4d23c99459e5",
+    "pk": "1ce21837-293f-4308-8e66-d50e575b4244",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "repo": "32416126-e127-4b7a-8042-ad9a47eb9d78",
-        "hash": "42",
-        "message": "a",
-        "author": "me"
+        "repo": "0d67c9eb-f386-45b5-8de0-1e319ddbdbe9",
+        "hash": "1337",
+        "message": "My w0rk3r",
+        "author": "Test user"
     }
 },
 {
     "model": "dataimport.revision",
-    "pk": "fe788ef9-0e48-4a1e-90e8-e2cbbfe3367f",
+    "pk": "e7458d87-7c82-4810-9add-327e5170d098",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "repo": "4730656e-3cda-4bd7-b6f8-73f8aec667c4",
-        "hash": "1337",
-        "message": "My w0rk3r",
-        "author": "Test user"
+        "repo": "6be4a57c-bef9-47ed-a13f-12a7bc9e4363",
+        "hash": "42",
+        "message": "a",
+        "author": "me"
     }
 },
 {
     "model": "dataimport.worker",
-    "pk": "1af12340-dd0c-4cc4-8bb6-b0d9da01e58b",
+    "pk": "641be872-7a57-46af-9fe0-322a43ede673",
     "fields": {
-        "name": "Document layout analyser",
-        "slug": "dla",
-        "type": "dla",
-        "repository": "4730656e-3cda-4bd7-b6f8-73f8aec667c4"
+        "name": "Recognizer",
+        "slug": "reco",
+        "type": "recognizer",
+        "repository": "0d67c9eb-f386-45b5-8de0-1e319ddbdbe9"
     }
 },
 {
     "model": "dataimport.worker",
-    "pk": "29026552-c9ed-4c8b-8b5f-84cc5ae18d2b",
+    "pk": "ca220722-ae75-4c9a-81ae-163575fb6ffe",
     "fields": {
-        "name": "Recognizer",
-        "slug": "reco",
-        "type": "recognizer",
-        "repository": "4730656e-3cda-4bd7-b6f8-73f8aec667c4"
+        "name": "Document layout analyser",
+        "slug": "dla",
+        "type": "dla",
+        "repository": "0d67c9eb-f386-45b5-8de0-1e319ddbdbe9"
     }
 },
 {
     "model": "dataimport.workerversion",
-    "pk": "9ce4bb8a-37ce-4a1d-84c8-55b23da22377",
+    "pk": "56497ab4-9948-4e86-8f6f-0173a99a438d",
     "fields": {
-        "worker": "1af12340-dd0c-4cc4-8bb6-b0d9da01e58b",
-        "revision": "fe788ef9-0e48-4a1e-90e8-e2cbbfe3367f",
+        "worker": "641be872-7a57-46af-9fe0-322a43ede673",
+        "revision": "1ce21837-293f-4308-8e66-d50e575b4244",
         "configuration": {
             "test": 42
         },
         "state": "available",
-        "docker_image": "2f612d65-6b97-4f7d-a91b-a901a88624e1",
+        "docker_image": "b57f1744-5f4f-40c0-baa8-0a6a5b91debf",
         "docker_image_iid": null
     }
 },
 {
     "model": "dataimport.workerversion",
-    "pk": "ae5a0896-a8d2-427b-be14-fd9130823851",
+    "pk": "8d3ff17d-c62d-4b30-afba-a1b80aca9110",
     "fields": {
-        "worker": "29026552-c9ed-4c8b-8b5f-84cc5ae18d2b",
-        "revision": "fe788ef9-0e48-4a1e-90e8-e2cbbfe3367f",
+        "worker": "ca220722-ae75-4c9a-81ae-163575fb6ffe",
+        "revision": "1ce21837-293f-4308-8e66-d50e575b4244",
         "configuration": {
             "test": 42
         },
         "state": "available",
-        "docker_image": "2f612d65-6b97-4f7d-a91b-a901a88624e1",
+        "docker_image": "b57f1744-5f4f-40c0-baa8-0a6a5b91debf",
         "docker_image_iid": null
     }
 },
 {
     "model": "documents.corpus",
-    "pk": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
+    "pk": "19d216db-0bf5-4201-8bed-c026760e2740",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "name": "Unit Tests",
         "description": "",
-        "repository": "32416126-e127-4b7a-8042-ad9a47eb9d78",
+        "repository": "6be4a57c-bef9-47ed-a13f-12a7bc9e4363",
         "public": true
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "6b750f47-efa2-4a49-9f9f-7f28474fc3e0",
+    "pk": "26a5f8c5-7b6e-40fc-8737-7889e58089b7",
     "fields": {
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
         "slug": "word",
         "display_name": "Word",
         "folder": false
@@ -117,870 +117,809 @@
 },
 {
     "model": "documents.elementtype",
-    "pk": "8bc8de12-809d-4f2e-acd8-fad0aafa7428",
+    "pk": "2e75a37c-7684-48ce-9d92-71252e82acee",
     "fields": {
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "slug": "surface",
-        "display_name": "Surface",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "slug": "text_line",
+        "display_name": "Line",
         "folder": false
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "d64f4c8d-2d15-4965-b0e2-54397dfcc0cb",
-    "fields": {
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "slug": "volume",
-        "display_name": "Volume",
-        "folder": true
-    }
-},
-{
-    "model": "documents.elementtype",
-    "pk": "baef17a0-86b7-4777-8f9c-c1a2512c42c5",
+    "pk": "6a87d0ef-72c9-4258-8937-11b7cf961c80",
     "fields": {
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "slug": "text_line",
-        "display_name": "Line",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "slug": "page",
+        "display_name": "Page",
         "folder": false
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "c5d070a5-7344-4de4-812b-28f2e3d8a970",
+    "pk": "b55c0cdb-2d49-46a0-8c4a-fb703d13cbe4",
     "fields": {
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "slug": "page",
-        "display_name": "Page",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "slug": "surface",
+        "display_name": "Surface",
         "folder": false
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "ec70e16c-4d4a-4108-8b86-1a9edceb9e87",
+    "pk": "c06e6532-6fa4-4feb-9fb7-f650270729b7",
     "fields": {
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
         "slug": "act",
         "display_name": "Act",
         "folder": false
     }
 },
 {
-    "model": "documents.elementpath",
-    "pk": "14cbb024-f6b2-4371-8933-42f6d17a86b5",
+    "model": "documents.elementtype",
+    "pk": "dbabef82-6beb-44e6-93ab-acbdbe41b8a7",
     "fields": {
-        "element": "8200fd63-c7e8-4724-8dc4-04b8168dd243",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\"]",
-        "ordering": 0
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "slug": "volume",
+        "display_name": "Volume",
+        "folder": true
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "16c1910f-64ae-40bc-92d4-0f2f537ced90",
+    "pk": "0ef38c90-ce48-44b6-985d-547b147a6714",
     "fields": {
-        "element": "4a780492-5a8b-437e-a002-f1572dd7520d",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\"]",
-        "ordering": 0
+        "element": "afabe9a4-0beb-4940-8106-040312a5513a",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\"]",
+        "ordering": 3
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "18c9eecf-1b1b-4dd6-be56-cacde3f44dab",
+    "pk": "121b9ece-32c7-499e-94c8-911cac40a923",
     "fields": {
-        "element": "2a5a1104-09a6-4189-9a7e-e306de03834a",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"8200fd63-c7e8-4724-8dc4-04b8168dd243\"]",
-        "ordering": 2
+        "element": "8334206a-2faa-436a-b9d7-95c3b29a3609",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"5c3f6332-e968-4c93-9f08-71f9615d37b7\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "2840f5ec-5b0c-4d3e-bd16-41e77f1e39b5",
+    "pk": "2928d9b3-6428-46c6-a4e5-38f72bd2e931",
     "fields": {
-        "element": "c66b0527-75ee-455e-a280-075bae7fb61a",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"8200fd63-c7e8-4724-8dc4-04b8168dd243\"]",
-        "ordering": 0
+        "element": "954c5e80-385f-4ca5-8f0e-6ce74152e1d5",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"5c3f6332-e968-4c93-9f08-71f9615d37b7\"]",
+        "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "287df024-4b40-43c1-b38c-b1c4dcb37884",
+    "pk": "2ac9289d-3ebd-4589-a028-97149bbac0cc",
     "fields": {
-        "element": "13cf31d6-5d9a-43c0-ade0-05fe0933cfcc",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"127daf48-f035-446f-bc3c-926b386c1fd5\"]",
+        "element": "38266757-13be-4e0c-99ba-32fd36629855",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"5c3f6332-e968-4c93-9f08-71f9615d37b7\"]",
         "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "304d552e-687c-4d84-b640-4f18787f67cf",
+    "pk": "315454d0-545f-4b13-a0d9-93b918875703",
     "fields": {
-        "element": "c3fd6c14-6714-4e39-bff5-21def7c76065",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"8200fd63-c7e8-4724-8dc4-04b8168dd243\"]",
+        "element": "4add78c5-5f00-4d2a-93d5-0998c8be3751",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"afabe9a4-0beb-4940-8106-040312a5513a\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "31459c9e-21d3-418e-8ab6-38627d61a100",
+    "pk": "38b060a0-62e9-406a-b050-6218c2c63ca0",
     "fields": {
-        "element": "829eec34-a36f-4cf1-a385-27dfc59efbeb",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\"]",
-        "ordering": 3
+        "element": "fa57c7e4-341d-4e3c-8b91-dc9244e83834",
+        "path": "[\"a4da8070-4487-4d8a-86d6-a71820b830c3\"]",
+        "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "338f4573-6cd3-4b60-bf8d-cfea7e113423",
+    "pk": "42cf85c6-bc8c-4c8a-8e3c-c4b6086ca4f6",
     "fields": {
-        "element": "ffa127a6-82f4-41f6-9041-2b6cb3bd27d6",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"b2401d97-cff8-45fd-a859-9ff72f5af322\"]",
-        "ordering": 0
+        "element": "21a72e94-d9fd-4e93-9b4e-c4049c6408ca",
+        "path": "[\"a4da8070-4487-4d8a-86d6-a71820b830c3\"]",
+        "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "39d1c344-1fc2-48b1-8be1-53882a0abef3",
+    "pk": "438bbfb9-14c6-4d0a-9f46-aa560a96a5cd",
     "fields": {
-        "element": "127daf48-f035-446f-bc3c-926b386c1fd5",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\"]",
+        "element": "e9e90d3e-90df-4fe3-a506-9188251d53ef",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\"]",
         "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "3d431978-8257-406d-8dce-ca7b766d2d0b",
+    "pk": "46411af2-48fd-4c8f-951f-5eaf9e0ec697",
     "fields": {
-        "element": "d843555c-4b00-486d-8fca-8f2bcf22bf51",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"17770006-9a53-410c-b2e8-4fd662d97f39\"]",
-        "ordering": 0
+        "element": "40565c74-238a-4c5b-91f5-21161ae9ae63",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"5d47a2a5-fd54-4f5b-b273-213d83010f78\"]",
+        "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "4df49c4c-c08e-4872-9a71-f1eed968cadb",
+    "pk": "59ceeda1-1538-4fb1-98c2-af83884e58bd",
     "fields": {
-        "element": "30dda265-4638-4e93-9ca9-c18da4b4b067",
-        "path": "[\"b1ef0e22-d9e5-4506-b9b8-ae04c0f0e9c9\"]",
+        "element": "207258a6-321a-4141-98ea-8dc21554bb17",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"5d47a2a5-fd54-4f5b-b273-213d83010f78\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "52cc2f64-afd4-44b4-a6ef-03b0c0b99f19",
+    "pk": "5b9da1d3-e282-4232-b743-5a2f39841972",
     "fields": {
-        "element": "fa3cfa49-01ea-4ab7-a5e0-dcc129289864",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"e0b3c9f2-753a-402a-8923-dfae7c630406\"]",
-        "ordering": 2
+        "element": "5d47a2a5-fd54-4f5b-b273-213d83010f78",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\"]",
+        "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "57b40d4a-41fd-49e8-8183-b5f8218c4040",
+    "pk": "7bd88606-f704-4f68-953d-a4f3d0607100",
     "fields": {
-        "element": "a43644ab-cd3d-4463-b237-f54b642fb747",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"17770006-9a53-410c-b2e8-4fd662d97f39\"]",
+        "element": "9d99261d-6bad-4ce0-8b38-322192718a99",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"e9e90d3e-90df-4fe3-a506-9188251d53ef\"]",
         "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "5ab81995-b3af-4b59-b327-11ae4510b81b",
+    "pk": "7cb5d566-b00f-4631-b461-6978a4346ebe",
     "fields": {
-        "element": "074c4f63-f6e2-4f0f-a5b3-8c9afc896a91",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"4a780492-5a8b-437e-a002-f1572dd7520d\"]",
-        "ordering": 0
+        "element": "35176f8f-e4da-46f6-8005-7602640c6662",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"dd8b4253-f67c-460e-9f49-a8ba3b76ab77\"]",
+        "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "7229f4d8-8082-4bb4-aaf0-0afc9b9f63a1",
+    "pk": "81bbbcbb-61ac-44b6-bedc-2946a4b58386",
     "fields": {
-        "element": "de95d376-b6a6-4145-8741-d22867d8f4ad",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"e0b3c9f2-753a-402a-8923-dfae7c630406\"]",
+        "element": "2a2992ce-ebaa-46b9-9198-ae65d4ac0bd2",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"dd8b4253-f67c-460e-9f49-a8ba3b76ab77\"]",
         "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "7674d247-d576-49fa-a5bf-ee217b38acc9",
+    "pk": "887c3223-854e-4249-9725-4cad8e6aead9",
     "fields": {
-        "element": "791f6f70-022c-4675-835b-d1b42a74ebca",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"8200fd63-c7e8-4724-8dc4-04b8168dd243\"]",
-        "ordering": 1
+        "element": "30df5c32-4d54-4eb7-839e-2775a9fee7d4",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"82f00bef-4432-4a56-aa0d-4691cd279e86\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "837569e5-bace-4e37-a0e4-4f35db89e8bb",
+    "pk": "8a05f6ed-6d8a-4783-8715-913b92cc0bf4",
     "fields": {
-        "element": "83e43013-f987-4374-ad1b-4187245846e5",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\"]",
-        "ordering": 2
+        "element": "82f00bef-4432-4a56-aa0d-4691cd279e86",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\"]",
+        "ordering": 4
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "899b8423-5c2f-418a-967f-d4ab41b27e09",
+    "pk": "8b8ca476-a21e-4850-bd2f-2de3c2c25b8d",
     "fields": {
-        "element": "d638b6a9-33fe-47dc-9bd4-f985d912fd20",
-        "path": "[\"b1ef0e22-d9e5-4506-b9b8-ae04c0f0e9c9\"]",
-        "ordering": 2
+        "element": "6629de9e-66ad-4ebd-970b-42c530a8fd24",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "a437870d-8142-438c-8702-b15e9d3db734",
+    "pk": "9ab04fdc-8148-4a9b-88fa-b1f77d6aec63",
     "fields": {
-        "element": "b2401d97-cff8-45fd-a859-9ff72f5af322",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\"]",
-        "ordering": 4
+        "element": "bef0c176-1bce-4409-84b3-1ea3632e91df",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\"]",
+        "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "ac98ff1a-1985-48c0-9474-0c4f959d04f2",
+    "pk": "b5521554-6375-47a2-a15a-fdba79587858",
     "fields": {
-        "element": "17770006-9a53-410c-b2e8-4fd662d97f39",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\"]",
+        "element": "5c3f6332-e968-4c93-9f08-71f9615d37b7",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\"]",
         "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "af214327-54bd-406f-92b4-6d42b9b9b504",
+    "pk": "b6e4863b-8562-47e1-a82f-dddeeb101f98",
     "fields": {
-        "element": "857c1df7-e89b-4329-a3d5-01585dd4aa94",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"83e43013-f987-4374-ad1b-4187245846e5\"]",
+        "element": "16b87335-f1a7-4aa6-9be9-be08d68d5fab",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"dd8b4253-f67c-460e-9f49-a8ba3b76ab77\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "bd13c121-11f3-4812-aeaa-17b6d16221dc",
+    "pk": "b9669a5b-aeba-4510-b5a4-804f5a41f512",
     "fields": {
-        "element": "1d5f2b0b-4c6e-47f4-a51b-6a349e9edecb",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"127daf48-f035-446f-bc3c-926b386c1fd5\"]",
+        "element": "9521fd3a-ab69-4bf5-9733-27c787719cbf",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"6629de9e-66ad-4ebd-970b-42c530a8fd24\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "c39a75e9-b229-4bf4-81e7-4cc6e6e1ac83",
+    "pk": "c2881e34-9df7-4b74-9b5e-2c8c830bb600",
     "fields": {
-        "element": "e0b3c9f2-753a-402a-8923-dfae7c630406",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\"]",
-        "ordering": 1
+        "element": "ac48a8b8-c152-45b7-9146-d8cc5952e61c",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"e9e90d3e-90df-4fe3-a506-9188251d53ef\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "cf020c8f-e78d-4360-9978-5ae68f5a2788",
+    "pk": "ce7b1d85-c02e-41a8-8091-c0c85a6cab17",
     "fields": {
-        "element": "e0f42ad4-6c5c-4ee7-a50e-e0394fb864fa",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"127daf48-f035-446f-bc3c-926b386c1fd5\"]",
-        "ordering": 2
+        "element": "e717601d-efbc-4fcd-96d2-7b8b23337369",
+        "path": "[\"a4da8070-4487-4d8a-86d6-a71820b830c3\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "cfe2f0bd-0bdc-43ec-8bb2-2d54761a1cba",
+    "pk": "f3022ca3-c9e6-40ec-8bcd-bb35b1e7104f",
     "fields": {
-        "element": "f082c5a6-5080-413b-a25a-9f5e44ffde36",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"e0b3c9f2-753a-402a-8923-dfae7c630406\"]",
+        "element": "89050cc4-f674-4b2c-a4ee-915f5ef60f8f",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"dd8b4253-f67c-460e-9f49-a8ba3b76ab77\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "e613a821-c8dc-4339-a426-aa857c29f894",
+    "pk": "f99e33e4-65fe-435e-93c9-08d3338012ad",
+    "fields": {
+        "element": "e8a3b377-90ad-4c9f-a53f-6bb52ade5339",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"e9e90d3e-90df-4fe3-a506-9188251d53ef\"]",
+        "ordering": 2
+    }
+},
+{
+    "model": "documents.elementpath",
+    "pk": "faf68d69-7b0c-4fda-b63d-870b0149fb8a",
     "fields": {
-        "element": "7feab108-63d6-49ba-9d58-56305cff534a",
-        "path": "[\"83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa\", \"829eec34-a36f-4cf1-a385-27dfc59efbeb\"]",
+        "element": "dd8b4253-f67c-460e-9f49-a8ba3b76ab77",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "fa8f0af2-ea9e-4b4e-88a7-6c4f1b695d9b",
+    "pk": "ffb9412e-5e5f-4913-94d8-74aff8522b2d",
     "fields": {
-        "element": "fb79b21b-76fb-4aa4-a80a-5ad3253343d8",
-        "path": "[\"b1ef0e22-d9e5-4506-b9b8-ae04c0f0e9c9\"]",
-        "ordering": 1
+        "element": "078bb096-ed24-4c4c-99bf-33a655d42d0a",
+        "path": "[\"cb49de2e-c4ed-43fa-a3e1-341f54400b24\", \"bef0c176-1bce-4409-84b3-1ea3632e91df\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.element",
-    "pk": "074c4f63-f6e2-4f0f-a5b3-8c9afc896a91",
+    "pk": "078bb096-ed24-4c4c-99bf-33a655d42d0a",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "8bc8de12-809d-4f2e-acd8-fad0aafa7428",
-        "name": "Surface A",
-        "zone": "cb095815-8630-42f0-b9c8-2bc7d4f171a9",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "b55c0cdb-2d49-46a0-8c4a-fb703d13cbe4",
+        "name": "Surface D",
+        "zone": "a9edc697-efc5-485a-adb5-bb36dd0a0a17",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "127daf48-f035-446f-bc3c-926b386c1fd5",
+    "pk": "16b87335-f1a7-4aa6-9be9-be08d68d5fab",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "c5d070a5-7344-4de4-812b-28f2e3d8a970",
-        "name": "Volume 1, page 2r",
-        "zone": "9e353033-4865-43ee-970c-111eb2711c22",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "26a5f8c5-7b6e-40fc-8737-7889e58089b7",
+        "name": "PARIS",
+        "zone": "becd66a9-ee22-4367-b6c9-6358c2912c52",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "13cf31d6-5d9a-43c0-ade0-05fe0933cfcc",
+    "pk": "207258a6-321a-4141-98ea-8dc21554bb17",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "6b750f47-efa2-4a49-9f9f-7f28474fc3e0",
-        "name": "ROY",
-        "zone": "856e0865-1bde-4dee-89be-3cf5372bbbab",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "b55c0cdb-2d49-46a0-8c4a-fb703d13cbe4",
+        "name": "Surface B",
+        "zone": "6145717e-e80d-4760-864e-b782eaf45cca",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "17770006-9a53-410c-b2e8-4fd662d97f39",
+    "pk": "21a72e94-d9fd-4e93-9b4e-c4049c6408ca",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "ec70e16c-4d4a-4108-8b86-1a9edceb9e87",
-        "name": "Act 2",
-        "zone": null,
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "6a87d0ef-72c9-4258-8937-11b7cf961c80",
+        "name": "Volume 2, page 2r",
+        "zone": "14609150-e063-496c-a48a-70e928a6a422",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "1d5f2b0b-4c6e-47f4-a51b-6a349e9edecb",
+    "pk": "2a2992ce-ebaa-46b9-9198-ae65d4ac0bd2",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "6b750f47-efa2-4a49-9f9f-7f28474fc3e0",
-        "name": "PARIS",
-        "zone": "f507c59b-7f7d-4acf-9125-5d880836c90e",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "26a5f8c5-7b6e-40fc-8737-7889e58089b7",
+        "name": "ROY",
+        "zone": "7756af28-e367-485c-a36d-4c632f2174f0",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "2a5a1104-09a6-4189-9a7e-e306de03834a",
+    "pk": "30df5c32-4d54-4eb7-839e-2775a9fee7d4",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "6b750f47-efa2-4a49-9f9f-7f28474fc3e0",
-        "name": "DATUM",
-        "zone": "678785d2-17f6-42bb-964a-3ad45da5d949",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "b55c0cdb-2d49-46a0-8c4a-fb703d13cbe4",
+        "name": "Surface F",
+        "zone": "ac0420ff-75b1-49a7-91c7-25cb46769bfa",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "30dda265-4638-4e93-9ca9-c18da4b4b067",
+    "pk": "35176f8f-e4da-46f6-8005-7602640c6662",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "c5d070a5-7344-4de4-812b-28f2e3d8a970",
-        "name": "Volume 2, page 1r",
-        "zone": "e06803f1-fd2b-4429-bfde-a143d561c20e",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "26a5f8c5-7b6e-40fc-8737-7889e58089b7",
+        "name": "DATUM",
+        "zone": "f19b4b3f-d528-46a2-86ee-0d414277c113",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "4a780492-5a8b-437e-a002-f1572dd7520d",
+    "pk": "38266757-13be-4e0c-99ba-32fd36629855",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "ec70e16c-4d4a-4108-8b86-1a9edceb9e87",
-        "name": "Act 1",
-        "zone": null,
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "26a5f8c5-7b6e-40fc-8737-7889e58089b7",
+        "name": "ROY",
+        "zone": "7b03ea23-ddc5-4e3e-944b-b95d189b7100",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "791f6f70-022c-4675-835b-d1b42a74ebca",
+    "pk": "40565c74-238a-4c5b-91f5-21161ae9ae63",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "6b750f47-efa2-4a49-9f9f-7f28474fc3e0",
-        "name": "ROY",
-        "zone": "dd3a3989-caac-42f2-b046-5835195b55d0",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "b55c0cdb-2d49-46a0-8c4a-fb703d13cbe4",
+        "name": "Surface C",
+        "zone": "a7fd8f0f-4b05-4e13-9ad4-94ea8b75fed2",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "7feab108-63d6-49ba-9d58-56305cff534a",
+    "pk": "4add78c5-5f00-4d2a-93d5-0998c8be3751",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "8bc8de12-809d-4f2e-acd8-fad0aafa7428",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "b55c0cdb-2d49-46a0-8c4a-fb703d13cbe4",
         "name": "Surface E",
-        "zone": "17c8ea0f-ed35-4bb0-ae27-c2b9468fc704",
-        "source": null,
+        "zone": "20f63840-ccfa-40a2-a6e9-425069bb77d5",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "8200fd63-c7e8-4724-8dc4-04b8168dd243",
+    "pk": "5c3f6332-e968-4c93-9f08-71f9615d37b7",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "c5d070a5-7344-4de4-812b-28f2e3d8a970",
-        "name": "Volume 1, page 1r",
-        "zone": "a715c81a-3010-428e-8e37-77701048de8e",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "6a87d0ef-72c9-4258-8937-11b7cf961c80",
+        "name": "Volume 1, page 1v",
+        "zone": "a7fd8f0f-4b05-4e13-9ad4-94ea8b75fed2",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "829eec34-a36f-4cf1-a385-27dfc59efbeb",
+    "pk": "5d47a2a5-fd54-4f5b-b273-213d83010f78",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "ec70e16c-4d4a-4108-8b86-1a9edceb9e87",
-        "name": "Act 4",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "c06e6532-6fa4-4feb-9fb7-f650270729b7",
+        "name": "Act 2",
         "zone": null,
-        "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "83a3df5a-25f0-4c6c-aae9-4d90eaf2f6fa",
+    "pk": "6629de9e-66ad-4ebd-970b-42c530a8fd24",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "d64f4c8d-2d15-4965-b0e2-54397dfcc0cb",
-        "name": "Volume 1",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "c06e6532-6fa4-4feb-9fb7-f650270729b7",
+        "name": "Act 1",
         "zone": null,
-        "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "83e43013-f987-4374-ad1b-4187245846e5",
+    "pk": "82f00bef-4432-4a56-aa0d-4691cd279e86",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "ec70e16c-4d4a-4108-8b86-1a9edceb9e87",
-        "name": "Act 3",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "c06e6532-6fa4-4feb-9fb7-f650270729b7",
+        "name": "Act 5",
         "zone": null,
-        "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "857c1df7-e89b-4329-a3d5-01585dd4aa94",
+    "pk": "8334206a-2faa-436a-b9d7-95c3b29a3609",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "8bc8de12-809d-4f2e-acd8-fad0aafa7428",
-        "name": "Surface D",
-        "zone": "a35697ac-d9ba-4d50-ae0c-caf98f2ffa79",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "26a5f8c5-7b6e-40fc-8737-7889e58089b7",
+        "name": "PARIS",
+        "zone": "12608b8e-f690-4366-8e95-642cd1def089",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "a43644ab-cd3d-4463-b237-f54b642fb747",
+    "pk": "89050cc4-f674-4b2c-a4ee-915f5ef60f8f",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "8bc8de12-809d-4f2e-acd8-fad0aafa7428",
-        "name": "Surface C",
-        "zone": "323e029a-1d5b-4cef-8776-0ad51266d7ed",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "2e75a37c-7684-48ce-9d92-71252e82acee",
+        "name": "Text line",
+        "zone": "7756af28-e367-485c-a36d-4c632f2174f0",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "b1ef0e22-d9e5-4506-b9b8-ae04c0f0e9c9",
+    "pk": "9521fd3a-ab69-4bf5-9733-27c787719cbf",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "d64f4c8d-2d15-4965-b0e2-54397dfcc0cb",
-        "name": "Volume 2",
-        "zone": null,
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "b55c0cdb-2d49-46a0-8c4a-fb703d13cbe4",
+        "name": "Surface A",
+        "zone": "2475cb82-3575-4f4b-b8a7-f034c96ca535",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "b2401d97-cff8-45fd-a859-9ff72f5af322",
+    "pk": "954c5e80-385f-4ca5-8f0e-6ce74152e1d5",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "ec70e16c-4d4a-4108-8b86-1a9edceb9e87",
-        "name": "Act 5",
-        "zone": null,
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "26a5f8c5-7b6e-40fc-8737-7889e58089b7",
+        "name": "DATUM",
+        "zone": "7bc4d869-31ec-480d-be01-b4db95f0457b",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "c3fd6c14-6714-4e39-bff5-21def7c76065",
+    "pk": "9d99261d-6bad-4ce0-8b38-322192718a99",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "baef17a0-86b7-4777-8f9c-c1a2512c42c5",
-        "name": "Text line",
-        "zone": "dd3a3989-caac-42f2-b046-5835195b55d0",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "26a5f8c5-7b6e-40fc-8737-7889e58089b7",
+        "name": "ROY",
+        "zone": "365ac12c-e4e2-4cfe-8deb-72e189fc29ab",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "c66b0527-75ee-455e-a280-075bae7fb61a",
+    "pk": "a4da8070-4487-4d8a-86d6-a71820b830c3",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "6b750f47-efa2-4a49-9f9f-7f28474fc3e0",
-        "name": "PARIS",
-        "zone": "fd25cbf5-7bbd-4411-b8b1-f1815474a09a",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "dbabef82-6beb-44e6-93ab-acbdbe41b8a7",
+        "name": "Volume 2",
+        "zone": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "d638b6a9-33fe-47dc-9bd4-f985d912fd20",
+    "pk": "ac48a8b8-c152-45b7-9146-d8cc5952e61c",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "c5d070a5-7344-4de4-812b-28f2e3d8a970",
-        "name": "Volume 2, page 2r",
-        "zone": "289df828-c2b7-4bb1-94a8-200c2b352df5",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "26a5f8c5-7b6e-40fc-8737-7889e58089b7",
+        "name": "PARIS",
+        "zone": "a575f5d6-c106-40ed-b012-2bd6fb0fda0a",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "d843555c-4b00-486d-8fca-8f2bcf22bf51",
+    "pk": "afabe9a4-0beb-4940-8106-040312a5513a",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "8bc8de12-809d-4f2e-acd8-fad0aafa7428",
-        "name": "Surface B",
-        "zone": "14858536-cb2f-44ec-9aaf-f954ed1a34ce",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "c06e6532-6fa4-4feb-9fb7-f650270729b7",
+        "name": "Act 4",
+        "zone": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "de95d376-b6a6-4145-8741-d22867d8f4ad",
+    "pk": "bef0c176-1bce-4409-84b3-1ea3632e91df",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "6b750f47-efa2-4a49-9f9f-7f28474fc3e0",
-        "name": "ROY",
-        "zone": "afe78b66-3b80-4431-9e30-b0f08691a366",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "c06e6532-6fa4-4feb-9fb7-f650270729b7",
+        "name": "Act 3",
+        "zone": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "e0b3c9f2-753a-402a-8923-dfae7c630406",
+    "pk": "cb49de2e-c4ed-43fa-a3e1-341f54400b24",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "c5d070a5-7344-4de4-812b-28f2e3d8a970",
-        "name": "Volume 1, page 1v",
-        "zone": "323e029a-1d5b-4cef-8776-0ad51266d7ed",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "dbabef82-6beb-44e6-93ab-acbdbe41b8a7",
+        "name": "Volume 1",
+        "zone": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "e0f42ad4-6c5c-4ee7-a50e-e0394fb864fa",
+    "pk": "dd8b4253-f67c-460e-9f49-a8ba3b76ab77",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "6b750f47-efa2-4a49-9f9f-7f28474fc3e0",
-        "name": "DATUM",
-        "zone": "b21b6855-6e47-4b89-9f7c-7611e7c857f3",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "6a87d0ef-72c9-4258-8937-11b7cf961c80",
+        "name": "Volume 1, page 1r",
+        "zone": "1d4b7799-44d2-411e-aab4-b6c0f93821c6",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "f082c5a6-5080-413b-a25a-9f5e44ffde36",
+    "pk": "e717601d-efbc-4fcd-96d2-7b8b23337369",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "6b750f47-efa2-4a49-9f9f-7f28474fc3e0",
-        "name": "PARIS",
-        "zone": "deefcad2-6b09-4214-90d4-3dc1e35b350b",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "6a87d0ef-72c9-4258-8937-11b7cf961c80",
+        "name": "Volume 2, page 1r",
+        "zone": "46a6d7c0-f4a9-4f47-b2ed-2cb77eac34c1",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "fa3cfa49-01ea-4ab7-a5e0-dcc129289864",
+    "pk": "e8a3b377-90ad-4c9f-a53f-6bb52ade5339",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "6b750f47-efa2-4a49-9f9f-7f28474fc3e0",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "26a5f8c5-7b6e-40fc-8737-7889e58089b7",
         "name": "DATUM",
-        "zone": "1f834158-327d-4eb0-9707-081c563142b0",
-        "source": null,
+        "zone": "82a7dd63-9427-4ae0-86cf-c07112d79a8a",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "fb79b21b-76fb-4aa4-a80a-5ad3253343d8",
+    "pk": "e9e90d3e-90df-4fe3-a506-9188251d53ef",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "c5d070a5-7344-4de4-812b-28f2e3d8a970",
-        "name": "Volume 2, page 1v",
-        "zone": "38b0be9b-d2e7-40ce-926e-29b7a9451a1a",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "6a87d0ef-72c9-4258-8937-11b7cf961c80",
+        "name": "Volume 1, page 2r",
+        "zone": "375de5ef-6093-411c-ac23-fd75e6aa7bee",
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "ffa127a6-82f4-41f6-9041-2b6cb3bd27d6",
+    "pk": "fa57c7e4-341d-4e3c-8b91-dc9244e83834",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "8bc8de12-809d-4f2e-acd8-fad0aafa7428",
-        "name": "Surface F",
-        "zone": "d2fec326-095d-4394-ba5b-063e03b4a1c6",
-        "source": null,
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "6a87d0ef-72c9-4258-8937-11b7cf961c80",
+        "name": "Volume 2, page 1v",
+        "zone": "c855d406-6d8d-4ac1-a233-c7e9a32d262e",
         "worker_version": null
     }
 },
-{
-    "model": "documents.datasource",
-    "pk": "772fd44c-5ea2-4af9-8172-03272a3ccef6",
-    "fields": {
-        "type": "classifier",
-        "slug": "test",
-        "name": "Test Classifier",
-        "revision": "5.1",
-        "internal": false
-    }
-},
-{
-    "model": "documents.datasource",
-    "pk": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-    "fields": {
-        "type": "recognizer",
-        "slug": "test",
-        "name": "Test Recognizer",
-        "revision": "4.2",
-        "internal": false
-    }
-},
 {
     "model": "documents.transcription",
-    "pk": "24927df2-8c29-4850-be42-916332c62e13",
+    "pk": "00096edb-2129-458f-acaf-52d13b4bac40",
     "fields": {
-        "element": "8200fd63-c7e8-4724-8dc4-04b8168dd243",
-        "source": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-        "worker_version": null,
-        "text": "Lorem ipsum dolor sit amet",
+        "element": "9d99261d-6bad-4ce0-8b38-322192718a99",
+        "worker_version": "56497ab4-9948-4e86-8f6f-0173a99a438d",
+        "text": "ROY",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "277bcdb9-a9b4-4b99-81fc-7bf35dafc99a",
+    "pk": "14fd7da5-4b45-4a87-9039-d6828c70b522",
     "fields": {
-        "element": "de95d376-b6a6-4145-8741-d22867d8f4ad",
-        "source": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-        "worker_version": null,
+        "element": "2a2992ce-ebaa-46b9-9198-ae65d4ac0bd2",
+        "worker_version": "56497ab4-9948-4e86-8f6f-0173a99a438d",
         "text": "ROY",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "6dba36d2-5a56-41e5-90e0-b930454f995f",
+    "pk": "572cd720-8d0c-4327-8def-274c15490805",
     "fields": {
-        "element": "e0f42ad4-6c5c-4ee7-a50e-e0394fb864fa",
-        "source": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-        "worker_version": null,
-        "text": "DATUM",
+        "element": "8334206a-2faa-436a-b9d7-95c3b29a3609",
+        "worker_version": "56497ab4-9948-4e86-8f6f-0173a99a438d",
+        "text": "PARIS",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "83832e84-8a84-491b-a84e-6dde77cb44ac",
+    "pk": "a277879a-c616-40e5-b872-af91752156b6",
     "fields": {
-        "element": "1d5f2b0b-4c6e-47f4-a51b-6a349e9edecb",
-        "source": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-        "worker_version": null,
-        "text": "PARIS",
+        "element": "35176f8f-e4da-46f6-8005-7602640c6662",
+        "worker_version": "56497ab4-9948-4e86-8f6f-0173a99a438d",
+        "text": "DATUM",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "8448ea5d-0935-40a6-991f-7f79f1d4b697",
+    "pk": "a6336be7-88dc-4087-b691-06607d9500a0",
     "fields": {
-        "element": "f082c5a6-5080-413b-a25a-9f5e44ffde36",
-        "source": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-        "worker_version": null,
-        "text": "PARIS",
+        "element": "954c5e80-385f-4ca5-8f0e-6ce74152e1d5",
+        "worker_version": "56497ab4-9948-4e86-8f6f-0173a99a438d",
+        "text": "DATUM",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "9f0daddd-3423-4298-b7f1-fa8f19806f15",
+    "pk": "bee9ea44-4b69-40bc-975d-0e764043db09",
     "fields": {
-        "element": "13cf31d6-5d9a-43c0-ade0-05fe0933cfcc",
-        "source": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-        "worker_version": null,
+        "element": "38266757-13be-4e0c-99ba-32fd36629855",
+        "worker_version": "56497ab4-9948-4e86-8f6f-0173a99a438d",
         "text": "ROY",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "adbcf82d-7d7e-4bfa-95e4-cf3ba9f44222",
+    "pk": "c082d297-b922-4c0a-8f58-87820c9154d9",
     "fields": {
-        "element": "c66b0527-75ee-455e-a280-075bae7fb61a",
-        "source": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-        "worker_version": null,
-        "text": "PARIS",
+        "element": "e8a3b377-90ad-4c9f-a53f-6bb52ade5339",
+        "worker_version": "56497ab4-9948-4e86-8f6f-0173a99a438d",
+        "text": "DATUM",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "ca4659bb-6456-47d8-bd58-68e6f77e6058",
+    "pk": "ca3bfab9-9889-4420-9cd5-7c3c38ea029f",
     "fields": {
-        "element": "2a5a1104-09a6-4189-9a7e-e306de03834a",
-        "source": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-        "worker_version": null,
-        "text": "DATUM",
+        "element": "16b87335-f1a7-4aa6-9be9-be08d68d5fab",
+        "worker_version": "56497ab4-9948-4e86-8f6f-0173a99a438d",
+        "text": "PARIS",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "ec4bb95f-4a37-467e-acdc-e166822f5f7b",
+    "pk": "cd8e3239-9913-41a6-b59c-f150477dcd1e",
     "fields": {
-        "element": "791f6f70-022c-4675-835b-d1b42a74ebca",
-        "source": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-        "worker_version": null,
-        "text": "ROY",
+        "element": "ac48a8b8-c152-45b7-9146-d8cc5952e61c",
+        "worker_version": "56497ab4-9948-4e86-8f6f-0173a99a438d",
+        "text": "PARIS",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "ff16ef70-d666-4c15-a483-d75f8d23531c",
+    "pk": "d0e2f6fc-823e-4ae3-aee1-bbdde6ed6e25",
     "fields": {
-        "element": "fa3cfa49-01ea-4ab7-a5e0-dcc129289864",
-        "source": "e313bb2d-e535-48aa-858c-10728ae3ef26",
-        "worker_version": null,
-        "text": "DATUM",
+        "element": "dd8b4253-f67c-460e-9f49-a8ba3b76ab77",
+        "worker_version": "56497ab4-9948-4e86-8f6f-0173a99a438d",
+        "text": "Lorem ipsum dolor sit amet",
         "score": 1.0
     }
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "5baf09ed-27d4-49f4-b824-4699db956f9f",
+    "pk": "36018d35-d38f-4784-ba80-e39f2773de20",
     "fields": {
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "location",
-        "name": "location"
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "text",
+        "name": "folio"
     }
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "6ecef8ac-a3bb-44de-9fa2-60171029fecf",
+    "pk": "6c4be36a-4ad6-4514-94ee-df5775cd2946",
     "fields": {
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
         "type": "date",
         "name": "date"
     }
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "745a55fa-e849-4aa8-9308-27bcc7970f57",
+    "pk": "8b198b6a-d2e6-4fba-b0eb-7fc03ea5c0e8",
     "fields": {
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
-        "type": "text",
-        "name": "folio"
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
+        "type": "location",
+        "name": "location"
     }
 },
 {
     "model": "documents.metadata",
-    "pk": "0f691996-a08f-4a9f-af74-fe8220f9abb9",
+    "pk": "09c1a87c-0d7f-429d-9842-083493292fd2",
     "fields": {
-        "element": "d638b6a9-33fe-47dc-9bd4-f985d912fd20",
+        "element": "5c3f6332-e968-4c93-9f08-71f9615d37b7",
         "name": "folio",
         "type": "text",
-        "value": "2r",
+        "value": "1v",
         "revision": null,
         "index": 0,
         "entity": null
@@ -988,12 +927,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "6768f88e-111f-45e1-9074-b0c1a0dea583",
+    "pk": "0ec9b034-8923-420e-a826-2908f9964238",
     "fields": {
-        "element": "4a780492-5a8b-437e-a002-f1572dd7520d",
+        "element": "afabe9a4-0beb-4940-8106-040312a5513a",
         "name": "number",
         "type": "text",
-        "value": "1",
+        "value": "4",
         "revision": null,
         "index": 0,
         "entity": null
@@ -1001,12 +940,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "7aae934a-2829-4a06-8364-cc0132551bbf",
+    "pk": "10e6d84c-e94f-444a-908a-2245f0453acf",
     "fields": {
-        "element": "b2401d97-cff8-45fd-a859-9ff72f5af322",
-        "name": "number",
+        "element": "e9e90d3e-90df-4fe3-a506-9188251d53ef",
+        "name": "folio",
         "type": "text",
-        "value": "5",
+        "value": "2r",
         "revision": null,
         "index": 0,
         "entity": null
@@ -1014,12 +953,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "8c82f260-b23e-4f80-bb64-d19d1d4858de",
+    "pk": "1a47f0de-cf9d-4440-b2cd-0f5448a7ac87",
     "fields": {
-        "element": "fb79b21b-76fb-4aa4-a80a-5ad3253343d8",
-        "name": "folio",
+        "element": "5d47a2a5-fd54-4f5b-b273-213d83010f78",
+        "name": "number",
         "type": "text",
-        "value": "1v",
+        "value": "2",
         "revision": null,
         "index": 0,
         "entity": null
@@ -1027,12 +966,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "9d783eca-9432-4ab5-85d8-2a35e20e92f5",
+    "pk": "2a8d9c1c-ea50-420f-8dd9-747344a03417",
     "fields": {
-        "element": "17770006-9a53-410c-b2e8-4fd662d97f39",
-        "name": "number",
+        "element": "21a72e94-d9fd-4e93-9b4e-c4049c6408ca",
+        "name": "folio",
         "type": "text",
-        "value": "2",
+        "value": "2r",
         "revision": null,
         "index": 0,
         "entity": null
@@ -1040,12 +979,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "c733a7d2-5e55-4c36-a7a0-6cf9f79fe7cd",
+    "pk": "3885c7fd-6254-4995-a8e4-dd23f62dcf46",
     "fields": {
-        "element": "e0b3c9f2-753a-402a-8923-dfae7c630406",
-        "name": "folio",
+        "element": "82f00bef-4432-4a56-aa0d-4691cd279e86",
+        "name": "number",
         "type": "text",
-        "value": "1v",
+        "value": "5",
         "revision": null,
         "index": 0,
         "entity": null
@@ -1053,12 +992,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "c783d362-df59-4042-802b-354c637ac771",
+    "pk": "3deb6fb2-a573-48a5-a4f9-19788a2fead6",
     "fields": {
-        "element": "8200fd63-c7e8-4724-8dc4-04b8168dd243",
+        "element": "fa57c7e4-341d-4e3c-8b91-dc9244e83834",
         "name": "folio",
         "type": "text",
-        "value": "1r",
+        "value": "1v",
         "revision": null,
         "index": 0,
         "entity": null
@@ -1066,12 +1005,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "d4bca037-d70f-4e70-9462-f61b346a2078",
+    "pk": "63d5dfd1-caad-4965-a62e-4c5c65c1c377",
     "fields": {
-        "element": "83e43013-f987-4374-ad1b-4187245846e5",
-        "name": "number",
+        "element": "e717601d-efbc-4fcd-96d2-7b8b23337369",
+        "name": "folio",
         "type": "text",
-        "value": "3",
+        "value": "1r",
         "revision": null,
         "index": 0,
         "entity": null
@@ -1079,12 +1018,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "e4aba6d5-735c-4cbf-9a51-0310cc6fe587",
+    "pk": "8afba47d-7d44-4be5-b06b-573cebac2e61",
     "fields": {
-        "element": "829eec34-a36f-4cf1-a385-27dfc59efbeb",
+        "element": "6629de9e-66ad-4ebd-970b-42c530a8fd24",
         "name": "number",
         "type": "text",
-        "value": "4",
+        "value": "1",
         "revision": null,
         "index": 0,
         "entity": null
@@ -1092,12 +1031,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "e8f3731e-5731-443f-a32a-0c7d5e978d72",
+    "pk": "e1bea3bf-ecee-420c-8ab5-fe844e604c78",
     "fields": {
-        "element": "30dda265-4638-4e93-9ca9-c18da4b4b067",
-        "name": "folio",
+        "element": "bef0c176-1bce-4409-84b3-1ea3632e91df",
+        "name": "number",
         "type": "text",
-        "value": "1r",
+        "value": "3",
         "revision": null,
         "index": 0,
         "entity": null
@@ -1105,12 +1044,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "f1bbb0fc-f377-42cf-9738-2cb9fac64fa6",
+    "pk": "e9ffe4db-7885-482a-91ba-7c2ec005b8ba",
     "fields": {
-        "element": "127daf48-f035-446f-bc3c-926b386c1fd5",
+        "element": "dd8b4253-f67c-460e-9f49-a8ba3b76ab77",
         "name": "folio",
         "type": "text",
-        "value": "2r",
+        "value": "1r",
         "revision": null,
         "index": 0,
         "entity": null
@@ -1134,7 +1073,7 @@
 },
 {
     "model": "images.image",
-    "pk": "015c8492-5aca-474f-961a-e7c8ad3466a3",
+    "pk": "4643992a-7a0f-4c49-8cef-dc0fdb153996",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -1148,12 +1087,12 @@
 },
 {
     "model": "images.image",
-    "pk": "5bcdc8df-671c-43a0-a644-0ee48dbd4ca2",
+    "pk": "51712108-93ad-47b4-b6b3-6359b805d816",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img3",
+        "path": "img4",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -1162,12 +1101,12 @@
 },
 {
     "model": "images.image",
-    "pk": "6766383c-c549-4506-b2f2-3f167e04252b",
+    "pk": "743f3fa5-1bfe-42de-9594-91586669e8c0",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img6",
+        "path": "img3",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -1176,12 +1115,12 @@
 },
 {
     "model": "images.image",
-    "pk": "9f0f0803-389d-4daf-bf5f-512fab2d4274",
+    "pk": "bffbd952-1c7d-4352-80df-aac54b59a552",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img4",
+        "path": "img1",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -1190,7 +1129,7 @@
 },
 {
     "model": "images.image",
-    "pk": "e5f640a5-3782-4780-8f4c-0f7f4985246e",
+    "pk": "f7cffb72-7890-45dc-a3cb-213f796ec73c",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -1204,12 +1143,12 @@
 },
 {
     "model": "images.image",
-    "pk": "ff1ff29f-5f94-4880-a318-dd864546f195",
+    "pk": "ffc1c120-cf3b-4b47-87ac-a9bb59225400",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img1",
+        "path": "img6",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -1218,234 +1157,234 @@
 },
 {
     "model": "images.zone",
-    "pk": "14858536-cb2f-44ec-9aaf-f954ed1a34ce",
+    "pk": "12608b8e-f690-4366-8e95-642cd1def089",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "ff1ff29f-5f94-4880-a318-dd864546f195",
-        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)"
+        "image": "4643992a-7a0f-4c49-8cef-dc0fdb153996",
+        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "17c8ea0f-ed35-4bb0-ae27-c2b9468fc704",
+    "pk": "14609150-e063-496c-a48a-70e928a6a422",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "5bcdc8df-671c-43a0-a644-0ee48dbd4ca2",
-        "polygon": "LINEARRING (300 300, 300 600, 600 600, 600 300, 300 300)"
+        "image": "ffc1c120-cf3b-4b47-87ac-a9bb59225400",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "1f834158-327d-4eb0-9707-081c563142b0",
+    "pk": "1d4b7799-44d2-411e-aab4-b6c0f93821c6",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "015c8492-5aca-474f-961a-e7c8ad3466a3",
-        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
+        "image": "bffbd952-1c7d-4352-80df-aac54b59a552",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "289df828-c2b7-4bb1-94a8-200c2b352df5",
+    "pk": "20f63840-ccfa-40a2-a6e9-425069bb77d5",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "6766383c-c549-4506-b2f2-3f167e04252b",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "743f3fa5-1bfe-42de-9594-91586669e8c0",
+        "polygon": "LINEARRING (300 300, 300 600, 600 600, 600 300, 300 300)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "323e029a-1d5b-4cef-8776-0ad51266d7ed",
+    "pk": "2475cb82-3575-4f4b-b8a7-f034c96ca535",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "015c8492-5aca-474f-961a-e7c8ad3466a3",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "bffbd952-1c7d-4352-80df-aac54b59a552",
+        "polygon": "LINEARRING (0 0, 0 600, 600 600, 600 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "38b0be9b-d2e7-40ce-926e-29b7a9451a1a",
+    "pk": "365ac12c-e4e2-4cfe-8deb-72e189fc29ab",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "e5f640a5-3782-4780-8f4c-0f7f4985246e",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "743f3fa5-1bfe-42de-9594-91586669e8c0",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "678785d2-17f6-42bb-964a-3ad45da5d949",
+    "pk": "375de5ef-6093-411c-ac23-fd75e6aa7bee",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "ff1ff29f-5f94-4880-a318-dd864546f195",
-        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
+        "image": "743f3fa5-1bfe-42de-9594-91586669e8c0",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "856e0865-1bde-4dee-89be-3cf5372bbbab",
+    "pk": "46a6d7c0-f4a9-4f47-b2ed-2cb77eac34c1",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "5bcdc8df-671c-43a0-a644-0ee48dbd4ca2",
-        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
+        "image": "51712108-93ad-47b4-b6b3-6359b805d816",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "9e353033-4865-43ee-970c-111eb2711c22",
+    "pk": "6145717e-e80d-4760-864e-b782eaf45cca",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "5bcdc8df-671c-43a0-a644-0ee48dbd4ca2",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "bffbd952-1c7d-4352-80df-aac54b59a552",
+        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "a35697ac-d9ba-4d50-ae0c-caf98f2ffa79",
+    "pk": "7756af28-e367-485c-a36d-4c632f2174f0",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "5bcdc8df-671c-43a0-a644-0ee48dbd4ca2",
-        "polygon": "LINEARRING (0 0, 0 300, 300 300, 300 0, 0 0)"
+        "image": "bffbd952-1c7d-4352-80df-aac54b59a552",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "a715c81a-3010-428e-8e37-77701048de8e",
+    "pk": "7b03ea23-ddc5-4e3e-944b-b95d189b7100",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "ff1ff29f-5f94-4880-a318-dd864546f195",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "4643992a-7a0f-4c49-8cef-dc0fdb153996",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "afe78b66-3b80-4431-9e30-b0f08691a366",
+    "pk": "7bc4d869-31ec-480d-be01-b4db95f0457b",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "015c8492-5aca-474f-961a-e7c8ad3466a3",
-        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
+        "image": "4643992a-7a0f-4c49-8cef-dc0fdb153996",
+        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "b21b6855-6e47-4b89-9f7c-7611e7c857f3",
+    "pk": "82a7dd63-9427-4ae0-86cf-c07112d79a8a",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "5bcdc8df-671c-43a0-a644-0ee48dbd4ca2",
+        "image": "743f3fa5-1bfe-42de-9594-91586669e8c0",
         "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "cb095815-8630-42f0-b9c8-2bc7d4f171a9",
+    "pk": "a575f5d6-c106-40ed-b012-2bd6fb0fda0a",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "ff1ff29f-5f94-4880-a318-dd864546f195",
-        "polygon": "LINEARRING (0 0, 0 600, 600 600, 600 0, 0 0)"
+        "image": "743f3fa5-1bfe-42de-9594-91586669e8c0",
+        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "d2fec326-095d-4394-ba5b-063e03b4a1c6",
+    "pk": "a7fd8f0f-4b05-4e13-9ad4-94ea8b75fed2",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "5bcdc8df-671c-43a0-a644-0ee48dbd4ca2",
-        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)"
+        "image": "4643992a-7a0f-4c49-8cef-dc0fdb153996",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "dd3a3989-caac-42f2-b046-5835195b55d0",
+    "pk": "a9edc697-efc5-485a-adb5-bb36dd0a0a17",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "ff1ff29f-5f94-4880-a318-dd864546f195",
-        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
+        "image": "743f3fa5-1bfe-42de-9594-91586669e8c0",
+        "polygon": "LINEARRING (0 0, 0 300, 300 300, 300 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "deefcad2-6b09-4214-90d4-3dc1e35b350b",
+    "pk": "ac0420ff-75b1-49a7-91c7-25cb46769bfa",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "015c8492-5aca-474f-961a-e7c8ad3466a3",
-        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
+        "image": "743f3fa5-1bfe-42de-9594-91586669e8c0",
+        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "e06803f1-fd2b-4429-bfde-a143d561c20e",
+    "pk": "becd66a9-ee22-4367-b6c9-6358c2912c52",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "9f0f0803-389d-4daf-bf5f-512fab2d4274",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "bffbd952-1c7d-4352-80df-aac54b59a552",
+        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "f507c59b-7f7d-4acf-9125-5d880836c90e",
+    "pk": "c855d406-6d8d-4ac1-a233-c7e9a32d262e",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "5bcdc8df-671c-43a0-a644-0ee48dbd4ca2",
-        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
+        "image": "f7cffb72-7890-45dc-a3cb-213f796ec73c",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "fd25cbf5-7bbd-4411-b8b1-f1815474a09a",
+    "pk": "f19b4b3f-d528-46a2-86ee-0d414277c113",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "ff1ff29f-5f94-4880-a318-dd864546f195",
-        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
+        "image": "bffbd952-1c7d-4352-80df-aac54b59a552",
+        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
     }
 },
 {
     "model": "users.right",
-    "pk": "2353198d-8b85-4e0e-9cb0-143677816c46",
+    "pk": "a20599bf-effe-4892-b6b0-50d5ce60a7af",
     "fields": {
-        "user": 5,
+        "user": 4,
         "group": null,
-        "content_type": 37,
-        "content_id": "ed2836d2-7576-403b-837e-3af7e8b1a8ae",
+        "content_type": 36,
+        "content_id": "6cd5e224-8ee8-450f-a215-5622cce87a44",
         "level": 50
     }
 },
 {
     "model": "users.right",
-    "pk": "261bee50-3f5c-45b4-954e-94324f2c89cc",
+    "pk": "dba88407-234b-4c45-b64f-3e0e9d588cdd",
     "fields": {
         "user": 3,
         "group": null,
-        "content_type": 37,
-        "content_id": "ed2836d2-7576-403b-837e-3af7e8b1a8ae",
+        "content_type": 36,
+        "content_id": "6cd5e224-8ee8-450f-a215-5622cce87a44",
         "level": 100
     }
 },
 {
     "model": "users.right",
-    "pk": "26c45a40-240b-4090-92df-e0443f1297b8",
+    "pk": "ef00bd5f-0cd5-44a6-8862-122b21043ca6",
     "fields": {
-        "user": 4,
+        "user": 5,
         "group": null,
-        "content_type": 37,
-        "content_id": "ed2836d2-7576-403b-837e-3af7e8b1a8ae",
+        "content_type": 36,
+        "content_id": "6cd5e224-8ee8-450f-a215-5622cce87a44",
         "level": 50
     }
 },
@@ -1453,7 +1392,7 @@
     "model": "users.user",
     "pk": 1,
     "fields": {
-        "password": "pbkdf2_sha256$216000$LuIx8UPn35hP$IIrSaRj9KbHz6cF4AGvPPMmgif0ctNrlDz9JKW+lTNI=",
+        "password": "pbkdf2_sha256$216000$5HCYQQTUiYQK$Huwppfbe4FL0m/dI+UrjGP30xdrYpvXcrZVoA3aw4SA=",
         "last_login": null,
         "email": "root@root.fr",
         "display_name": "Admin",
@@ -1468,7 +1407,7 @@
     "model": "users.user",
     "pk": 2,
     "fields": {
-        "password": "pbkdf2_sha256$216000$g6La1np2jsjr$K7sK1pAk8oed4EFCYpni6zpeTyM7vD+C95G4zgtAEq8=",
+        "password": "pbkdf2_sha256$216000$vAk0dfJFqmDW$LwC94yP9WsnRA+bgOUk1O5eyb0BmmrgNAfpSox+xPSk=",
         "last_login": null,
         "email": "internal@internal.fr",
         "display_name": "Internal user",
@@ -1483,7 +1422,7 @@
     "model": "users.user",
     "pk": 3,
     "fields": {
-        "password": "pbkdf2_sha256$216000$5qVMEjobtNAi$f9GwxVUGxEnPzK7KSJvp2j7oY8DFs24tmCWBr/otIPc=",
+        "password": "pbkdf2_sha256$216000$CwM0wbXBUd7z$OccAsQS1VX5iDWngjImfnefhKrcXnP0RO3M2fj9jBTQ=",
         "last_login": null,
         "email": "user@user.fr",
         "display_name": "Test user",
@@ -1526,7 +1465,7 @@
 },
 {
     "model": "users.group",
-    "pk": "ed2836d2-7576-403b-837e-3af7e8b1a8ae",
+    "pk": "6cd5e224-8ee8-450f-a215-5622cce87a44",
     "fields": {
         "name": "User group",
         "public": false
@@ -1534,7 +1473,7 @@
 },
 {
     "model": "users.oauthcredentials",
-    "pk": "e0910bb1-91f7-4672-a51f-888ad5173fdd",
+    "pk": "f0fc6a6d-288b-40bb-9f3c-d90843627f01",
     "fields": {
         "user": 3,
         "provider_name": "gitlab",
@@ -1551,7 +1490,7 @@
     "pk": 1,
     "fields": {
         "user": 3,
-        "corpus": "3ea05d94-46b0-4270-a0be-2dfa7983edc5",
+        "corpus": "19d216db-0bf5-4201-8bed-c026760e2740",
         "can_write": true,
         "can_admin": true
     }
@@ -2279,978 +2218,942 @@
 {
     "model": "auth.permission",
     "pk": 81,
-    "fields": {
-        "name": "Can add data source",
-        "content_type": 21,
-        "codename": "add_datasource"
-    }
-},
-{
-    "model": "auth.permission",
-    "pk": 82,
-    "fields": {
-        "name": "Can change data source",
-        "content_type": 21,
-        "codename": "change_datasource"
-    }
-},
-{
-    "model": "auth.permission",
-    "pk": 83,
-    "fields": {
-        "name": "Can delete data source",
-        "content_type": 21,
-        "codename": "delete_datasource"
-    }
-},
-{
-    "model": "auth.permission",
-    "pk": 84,
-    "fields": {
-        "name": "Can view data source",
-        "content_type": 21,
-        "codename": "view_datasource"
-    }
-},
-{
-    "model": "auth.permission",
-    "pk": 85,
     "fields": {
         "name": "Can add element",
-        "content_type": 22,
+        "content_type": 21,
         "codename": "add_element"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 86,
+    "pk": 82,
     "fields": {
         "name": "Can change element",
-        "content_type": 22,
+        "content_type": 21,
         "codename": "change_element"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 87,
+    "pk": 83,
     "fields": {
         "name": "Can delete element",
-        "content_type": 22,
+        "content_type": 21,
         "codename": "delete_element"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 88,
+    "pk": 84,
     "fields": {
         "name": "Can view element",
-        "content_type": 22,
+        "content_type": 21,
         "codename": "view_element"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 89,
+    "pk": 85,
     "fields": {
         "name": "Can add element path",
-        "content_type": 23,
+        "content_type": 22,
         "codename": "add_elementpath"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 90,
+    "pk": 86,
     "fields": {
         "name": "Can change element path",
-        "content_type": 23,
+        "content_type": 22,
         "codename": "change_elementpath"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 91,
+    "pk": 87,
     "fields": {
         "name": "Can delete element path",
-        "content_type": 23,
+        "content_type": 22,
         "codename": "delete_elementpath"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 92,
+    "pk": 88,
     "fields": {
         "name": "Can view element path",
-        "content_type": 23,
+        "content_type": 22,
         "codename": "view_elementpath"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 93,
+    "pk": 89,
     "fields": {
         "name": "Can add element type",
-        "content_type": 24,
+        "content_type": 23,
         "codename": "add_elementtype"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 94,
+    "pk": 90,
     "fields": {
         "name": "Can change element type",
-        "content_type": 24,
+        "content_type": 23,
         "codename": "change_elementtype"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 95,
+    "pk": 91,
     "fields": {
         "name": "Can delete element type",
-        "content_type": 24,
+        "content_type": 23,
         "codename": "delete_elementtype"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 96,
+    "pk": 92,
     "fields": {
         "name": "Can view element type",
-        "content_type": 24,
+        "content_type": 23,
         "codename": "view_elementtype"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 97,
+    "pk": 93,
     "fields": {
         "name": "Can add entity",
-        "content_type": 25,
+        "content_type": 24,
         "codename": "add_entity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 98,
+    "pk": 94,
     "fields": {
         "name": "Can change entity",
-        "content_type": 25,
+        "content_type": 24,
         "codename": "change_entity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 99,
+    "pk": 95,
     "fields": {
         "name": "Can delete entity",
-        "content_type": 25,
+        "content_type": 24,
         "codename": "delete_entity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 100,
+    "pk": 96,
     "fields": {
         "name": "Can view entity",
-        "content_type": 25,
+        "content_type": 24,
         "codename": "view_entity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 101,
+    "pk": 97,
     "fields": {
         "name": "Can add ml class",
-        "content_type": 26,
+        "content_type": 25,
         "codename": "add_mlclass"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 102,
+    "pk": 98,
     "fields": {
         "name": "Can change ml class",
-        "content_type": 26,
+        "content_type": 25,
         "codename": "change_mlclass"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 103,
+    "pk": 99,
     "fields": {
         "name": "Can delete ml class",
-        "content_type": 26,
+        "content_type": 25,
         "codename": "delete_mlclass"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 104,
+    "pk": 100,
     "fields": {
         "name": "Can view ml class",
-        "content_type": 26,
+        "content_type": 25,
         "codename": "view_mlclass"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 105,
+    "pk": 101,
     "fields": {
         "name": "Can add transcription",
-        "content_type": 27,
+        "content_type": 26,
         "codename": "add_transcription"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 106,
+    "pk": 102,
     "fields": {
         "name": "Can change transcription",
-        "content_type": 27,
+        "content_type": 26,
         "codename": "change_transcription"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 107,
+    "pk": 103,
     "fields": {
         "name": "Can delete transcription",
-        "content_type": 27,
+        "content_type": 26,
         "codename": "delete_transcription"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 108,
+    "pk": 104,
     "fields": {
         "name": "Can view transcription",
-        "content_type": 27,
+        "content_type": 26,
         "codename": "view_transcription"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 109,
+    "pk": 105,
     "fields": {
         "name": "Can add transcription entity",
-        "content_type": 28,
+        "content_type": 27,
         "codename": "add_transcriptionentity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 110,
+    "pk": 106,
     "fields": {
         "name": "Can change transcription entity",
-        "content_type": 28,
+        "content_type": 27,
         "codename": "change_transcriptionentity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 111,
+    "pk": 107,
     "fields": {
         "name": "Can delete transcription entity",
-        "content_type": 28,
+        "content_type": 27,
         "codename": "delete_transcriptionentity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 112,
+    "pk": 108,
     "fields": {
         "name": "Can view transcription entity",
-        "content_type": 28,
+        "content_type": 27,
         "codename": "view_transcriptionentity"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 113,
+    "pk": 109,
     "fields": {
         "name": "Can add meta data",
-        "content_type": 29,
+        "content_type": 28,
         "codename": "add_metadata"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 114,
+    "pk": 110,
     "fields": {
         "name": "Can change meta data",
-        "content_type": 29,
+        "content_type": 28,
         "codename": "change_metadata"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 115,
+    "pk": 111,
     "fields": {
         "name": "Can delete meta data",
-        "content_type": 29,
+        "content_type": 28,
         "codename": "delete_metadata"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 116,
+    "pk": 112,
     "fields": {
         "name": "Can view meta data",
-        "content_type": 29,
+        "content_type": 28,
         "codename": "view_metadata"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 117,
+    "pk": 113,
     "fields": {
         "name": "Can add entity role",
-        "content_type": 30,
+        "content_type": 29,
         "codename": "add_entityrole"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 118,
+    "pk": 114,
     "fields": {
         "name": "Can change entity role",
-        "content_type": 30,
+        "content_type": 29,
         "codename": "change_entityrole"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 119,
+    "pk": 115,
     "fields": {
         "name": "Can delete entity role",
-        "content_type": 30,
+        "content_type": 29,
         "codename": "delete_entityrole"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 120,
+    "pk": 116,
     "fields": {
         "name": "Can view entity role",
-        "content_type": 30,
+        "content_type": 29,
         "codename": "view_entityrole"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 121,
+    "pk": 117,
     "fields": {
         "name": "Can add entity link",
-        "content_type": 31,
+        "content_type": 30,
         "codename": "add_entitylink"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 122,
+    "pk": 118,
     "fields": {
         "name": "Can change entity link",
-        "content_type": 31,
+        "content_type": 30,
         "codename": "change_entitylink"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 123,
+    "pk": 119,
     "fields": {
         "name": "Can delete entity link",
-        "content_type": 31,
+        "content_type": 30,
         "codename": "delete_entitylink"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 124,
+    "pk": 120,
     "fields": {
         "name": "Can view entity link",
-        "content_type": 31,
+        "content_type": 30,
         "codename": "view_entitylink"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 125,
+    "pk": 121,
     "fields": {
         "name": "Can add selection",
-        "content_type": 32,
+        "content_type": 31,
         "codename": "add_selection"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 126,
+    "pk": 122,
     "fields": {
         "name": "Can change selection",
-        "content_type": 32,
+        "content_type": 31,
         "codename": "change_selection"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 127,
+    "pk": 123,
     "fields": {
         "name": "Can delete selection",
-        "content_type": 32,
+        "content_type": 31,
         "codename": "delete_selection"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 128,
+    "pk": 124,
     "fields": {
         "name": "Can view selection",
-        "content_type": 32,
+        "content_type": 31,
         "codename": "view_selection"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 129,
+    "pk": 125,
     "fields": {
         "name": "Can add user",
-        "content_type": 33,
+        "content_type": 32,
         "codename": "add_user"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 130,
+    "pk": 126,
     "fields": {
         "name": "Can change user",
-        "content_type": 33,
+        "content_type": 32,
         "codename": "change_user"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 131,
+    "pk": 127,
     "fields": {
         "name": "Can delete user",
-        "content_type": 33,
+        "content_type": 32,
         "codename": "delete_user"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 132,
+    "pk": 128,
     "fields": {
         "name": "Can view user",
-        "content_type": 33,
+        "content_type": 32,
         "codename": "view_user"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 133,
+    "pk": 129,
     "fields": {
         "name": "Can add o auth credentials",
-        "content_type": 34,
+        "content_type": 33,
         "codename": "add_oauthcredentials"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 134,
+    "pk": 130,
     "fields": {
         "name": "Can change o auth credentials",
-        "content_type": 34,
+        "content_type": 33,
         "codename": "change_oauthcredentials"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 135,
+    "pk": 131,
     "fields": {
         "name": "Can delete o auth credentials",
-        "content_type": 34,
+        "content_type": 33,
         "codename": "delete_oauthcredentials"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 136,
+    "pk": 132,
     "fields": {
         "name": "Can view o auth credentials",
-        "content_type": 34,
+        "content_type": 33,
         "codename": "view_oauthcredentials"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 137,
+    "pk": 133,
     "fields": {
         "name": "Can add corpus right",
-        "content_type": 35,
+        "content_type": 34,
         "codename": "add_corpusright"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 138,
+    "pk": 134,
     "fields": {
         "name": "Can change corpus right",
-        "content_type": 35,
+        "content_type": 34,
         "codename": "change_corpusright"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 139,
+    "pk": 135,
     "fields": {
         "name": "Can delete corpus right",
-        "content_type": 35,
+        "content_type": 34,
         "codename": "delete_corpusright"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 140,
+    "pk": 136,
     "fields": {
         "name": "Can view corpus right",
-        "content_type": 35,
+        "content_type": 34,
         "codename": "view_corpusright"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 141,
+    "pk": 137,
     "fields": {
         "name": "Can add user scope",
-        "content_type": 36,
+        "content_type": 35,
         "codename": "add_userscope"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 142,
+    "pk": 138,
     "fields": {
         "name": "Can change user scope",
-        "content_type": 36,
+        "content_type": 35,
         "codename": "change_userscope"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 143,
+    "pk": 139,
     "fields": {
         "name": "Can delete user scope",
-        "content_type": 36,
+        "content_type": 35,
         "codename": "delete_userscope"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 144,
+    "pk": 140,
     "fields": {
         "name": "Can view user scope",
-        "content_type": 36,
+        "content_type": 35,
         "codename": "view_userscope"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 145,
+    "pk": 141,
     "fields": {
         "name": "Can add group",
-        "content_type": 37,
+        "content_type": 36,
         "codename": "add_group"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 146,
+    "pk": 142,
     "fields": {
         "name": "Can change group",
-        "content_type": 37,
+        "content_type": 36,
         "codename": "change_group"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 147,
+    "pk": 143,
     "fields": {
         "name": "Can delete group",
-        "content_type": 37,
+        "content_type": 36,
         "codename": "delete_group"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 148,
+    "pk": 144,
     "fields": {
         "name": "Can view group",
-        "content_type": 37,
+        "content_type": 36,
         "codename": "view_group"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 149,
+    "pk": 145,
     "fields": {
         "name": "Can add right",
-        "content_type": 38,
+        "content_type": 37,
         "codename": "add_right"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 150,
+    "pk": 146,
     "fields": {
         "name": "Can change right",
-        "content_type": 38,
+        "content_type": 37,
         "codename": "change_right"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 151,
+    "pk": 147,
     "fields": {
         "name": "Can delete right",
-        "content_type": 38,
+        "content_type": 37,
         "codename": "delete_right"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 152,
+    "pk": 148,
     "fields": {
         "name": "Can view right",
-        "content_type": 38,
+        "content_type": 37,
         "codename": "view_right"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 153,
+    "pk": 149,
     "fields": {
         "name": "Can add data file",
-        "content_type": 39,
+        "content_type": 38,
         "codename": "add_datafile"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 154,
+    "pk": 150,
     "fields": {
         "name": "Can change data file",
-        "content_type": 39,
+        "content_type": 38,
         "codename": "change_datafile"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 155,
+    "pk": 151,
     "fields": {
         "name": "Can delete data file",
-        "content_type": 39,
+        "content_type": 38,
         "codename": "delete_datafile"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 156,
+    "pk": 152,
     "fields": {
         "name": "Can view data file",
-        "content_type": 39,
+        "content_type": 38,
         "codename": "view_datafile"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 157,
+    "pk": 153,
     "fields": {
         "name": "Can add data import",
-        "content_type": 40,
+        "content_type": 39,
         "codename": "add_dataimport"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 158,
+    "pk": 154,
     "fields": {
         "name": "Can change data import",
-        "content_type": 40,
+        "content_type": 39,
         "codename": "change_dataimport"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 159,
+    "pk": 155,
     "fields": {
         "name": "Can delete data import",
-        "content_type": 40,
+        "content_type": 39,
         "codename": "delete_dataimport"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 160,
+    "pk": 156,
     "fields": {
         "name": "Can view data import",
-        "content_type": 40,
+        "content_type": 39,
         "codename": "view_dataimport"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 161,
+    "pk": 157,
     "fields": {
         "name": "Can add repository",
-        "content_type": 41,
+        "content_type": 40,
         "codename": "add_repository"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 162,
+    "pk": 158,
     "fields": {
         "name": "Can change repository",
-        "content_type": 41,
+        "content_type": 40,
         "codename": "change_repository"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 163,
+    "pk": 159,
     "fields": {
         "name": "Can delete repository",
-        "content_type": 41,
+        "content_type": 40,
         "codename": "delete_repository"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 164,
+    "pk": 160,
     "fields": {
         "name": "Can view repository",
-        "content_type": 41,
+        "content_type": 40,
         "codename": "view_repository"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 165,
+    "pk": 161,
     "fields": {
         "name": "Can add revision",
-        "content_type": 42,
+        "content_type": 41,
         "codename": "add_revision"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 166,
+    "pk": 162,
     "fields": {
         "name": "Can change revision",
-        "content_type": 42,
+        "content_type": 41,
         "codename": "change_revision"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 167,
+    "pk": 163,
     "fields": {
         "name": "Can delete revision",
-        "content_type": 42,
+        "content_type": 41,
         "codename": "delete_revision"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 168,
+    "pk": 164,
     "fields": {
         "name": "Can view revision",
-        "content_type": 42,
+        "content_type": 41,
         "codename": "view_revision"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 169,
+    "pk": 165,
     "fields": {
         "name": "Can add worker",
-        "content_type": 43,
+        "content_type": 42,
         "codename": "add_worker"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 170,
+    "pk": 166,
     "fields": {
         "name": "Can change worker",
-        "content_type": 43,
+        "content_type": 42,
         "codename": "change_worker"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 171,
+    "pk": 167,
     "fields": {
         "name": "Can delete worker",
-        "content_type": 43,
+        "content_type": 42,
         "codename": "delete_worker"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 172,
+    "pk": 168,
     "fields": {
         "name": "Can view worker",
-        "content_type": 43,
+        "content_type": 42,
         "codename": "view_worker"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 173,
+    "pk": 169,
     "fields": {
         "name": "Can add worker version",
-        "content_type": 44,
+        "content_type": 43,
         "codename": "add_workerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 174,
+    "pk": 170,
     "fields": {
         "name": "Can change worker version",
-        "content_type": 44,
+        "content_type": 43,
         "codename": "change_workerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 175,
+    "pk": 171,
     "fields": {
         "name": "Can delete worker version",
-        "content_type": 44,
+        "content_type": 43,
         "codename": "delete_workerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 176,
+    "pk": 172,
     "fields": {
         "name": "Can view worker version",
-        "content_type": 44,
+        "content_type": 43,
         "codename": "view_workerversion"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 177,
+    "pk": 173,
     "fields": {
         "name": "Can add git ref",
-        "content_type": 45,
+        "content_type": 44,
         "codename": "add_gitref"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 178,
+    "pk": 174,
     "fields": {
         "name": "Can change git ref",
-        "content_type": 45,
+        "content_type": 44,
         "codename": "change_gitref"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 179,
+    "pk": 175,
     "fields": {
         "name": "Can delete git ref",
-        "content_type": 45,
+        "content_type": 44,
         "codename": "delete_gitref"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 180,
+    "pk": 176,
     "fields": {
         "name": "Can view git ref",
-        "content_type": 45,
+        "content_type": 44,
         "codename": "view_gitref"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 181,
+    "pk": 177,
     "fields": {
         "name": "Can add worker run",
-        "content_type": 46,
+        "content_type": 45,
         "codename": "add_workerrun"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 182,
+    "pk": 178,
     "fields": {
         "name": "Can change worker run",
-        "content_type": 46,
+        "content_type": 45,
         "codename": "change_workerrun"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 183,
+    "pk": 179,
     "fields": {
         "name": "Can delete worker run",
-        "content_type": 46,
+        "content_type": 45,
         "codename": "delete_workerrun"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 184,
+    "pk": 180,
     "fields": {
         "name": "Can view worker run",
-        "content_type": 46,
+        "content_type": 45,
         "codename": "view_workerrun"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 185,
+    "pk": 181,
     "fields": {
         "name": "Can add data import element",
-        "content_type": 47,
+        "content_type": 46,
         "codename": "add_dataimportelement"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 186,
+    "pk": 182,
     "fields": {
         "name": "Can change data import element",
-        "content_type": 47,
+        "content_type": 46,
         "codename": "change_dataimportelement"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 187,
+    "pk": 183,
     "fields": {
         "name": "Can delete data import element",
-        "content_type": 47,
+        "content_type": 46,
         "codename": "delete_dataimportelement"
     }
 },
 {
     "model": "auth.permission",
-    "pk": 188,
+    "pk": 184,
     "fields": {
         "name": "Can view data import element",
-        "content_type": 47,
+        "content_type": 46,
         "codename": "view_dataimportelement"
     }
 },
 {
     "model": "ponos.workflow",
-    "pk": "21cc38da-a445-458c-8d09-c6a1c2f37eee",
+    "pk": "f46c2ffd-0c60-492d-9634-60dc935edc45",
     "fields": {
         "recipe": "tasks:\n docker_build:\n  image: reco",
         "created": "2020-02-02T01:23:45.678Z",
@@ -3259,7 +3162,7 @@
 },
 {
     "model": "ponos.task",
-    "pk": "ce2b799e-2c3b-4c1e-80e6-9833c4c67cae",
+    "pk": "7a8773e3-591d-43ac-94b6-56fb118a9dea",
     "fields": {
         "run": 0,
         "depth": 0,
@@ -3273,7 +3176,7 @@
         "image_artifact": null,
         "agent": null,
         "gpu": null,
-        "workflow": "21cc38da-a445-458c-8d09-c6a1c2f37eee",
+        "workflow": "f46c2ffd-0c60-492d-9634-60dc935edc45",
         "container": null,
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
@@ -3282,9 +3185,9 @@
 },
 {
     "model": "ponos.artifact",
-    "pk": "2f612d65-6b97-4f7d-a91b-a901a88624e1",
+    "pk": "b57f1744-5f4f-40c0-baa8-0a6a5b91debf",
     "fields": {
-        "task": "ce2b799e-2c3b-4c1e-80e6-9833c4c67cae",
+        "task": "7a8773e3-591d-43ac-94b6-56fb118a9dea",
         "path": "/path/to/docker_build",
         "size": 42000,
         "content_type": "application/octet-stream",
diff --git a/arkindex/documents/management/commands/build_fixtures.py b/arkindex/documents/management/commands/build_fixtures.py
index 37fa71b52a784f54e3e03984baa86e9a5f01616c..bcc219736f2decbd14098ec360beb853ce25dea5 100644
--- a/arkindex/documents/management/commands/build_fixtures.py
+++ b/arkindex/documents/management/commands/build_fixtures.py
@@ -7,11 +7,10 @@ from django.core.management.base import BaseCommand
 from django.utils import timezone as DjangoTimeZone
 
 from arkindex.dataimport.models import RepositoryType, WorkerVersion, WorkerVersionState, Workflow
-from arkindex.documents.models import Corpus, DataSource, Element, MetaData
+from arkindex.documents.models import Corpus, Element, MetaData
 from arkindex.images.models import Image, ImageServer, Zone
 from arkindex.users.models import CorpusRight, Group, User
 from arkindex_common.enums import MetaType
-from arkindex_common.ml_tool import MLToolType
 from ponos.models import State
 
 
@@ -90,24 +89,6 @@ class Command(BaseCommand):
             level=50
         )
 
-        # Create 1 data source for transcriptions
-        recognizer_source = DataSource.objects.create(
-            type=MLToolType.Recognizer,
-            slug='test',
-            name='Test Recognizer',
-            revision='4.2',
-            internal=False,
-        )
-
-        # Create 1 data source for classifications
-        DataSource.objects.create(
-            type=MLToolType.Classifier,
-            slug='test',
-            name='Test Classifier',
-            revision='5.1',
-            internal=False,
-        )
-
         # Create OAuth credentials for a user
         creds = user.credentials.create(
             provider_name='gitlab',
@@ -115,6 +96,50 @@ class Command(BaseCommand):
             token='oauth-token',
         )
 
+        # Create a worker repository
+        worker_repo = creds.repos.create(
+            type=RepositoryType.Worker,
+            url="http://my_repo.fake/workers/worker",
+            hook_token='worker-hook-token',
+            provider_name='GitLabProvider'
+        )
+
+        # Create a revision on this repository
+        revision = worker_repo.revisions.create(
+            hash="1337",
+            message="My w0rk3r",
+            author="Test user"
+        )
+
+        # Create a fake docker build with a docker image task
+        workflow = Workflow.objects.create(recipe='tasks:\n docker_build:\n  image: reco')
+        build_task = workflow.tasks.create(run=0, depth=0, slug='docker_build', state=State.Completed)
+        docker_image = build_task.artifacts.create(size=42_000, path='/path/to/docker_build')
+
+        # Create two workers for the repository with their available version
+        recognizer_worker = WorkerVersion.objects.create(
+            worker=worker_repo.workers.create(
+                name='Recognizer',
+                slug='reco',
+                type='recognizer',
+            ),
+            revision=revision,
+            configuration={'test': 42},
+            state=WorkerVersionState.Available,
+            docker_image=docker_image
+        )
+        WorkerVersion.objects.create(
+            worker=worker_repo.workers.create(
+                name='Document layout analyser',
+                slug='dla',
+                type='dla',
+            ),
+            revision=revision,
+            configuration={'test': 42},
+            state=WorkerVersionState.Available,
+            docker_image=docker_image
+        )
+
         # Create a IIIF repository
         repo = creds.repos.create(
             url='http://gitlab/repo',
@@ -245,14 +270,14 @@ class Command(BaseCommand):
                 )
                 element.add_parent(page)
                 element.transcriptions.create(
-                    source=recognizer_source,
+                    worker_version=recognizer_worker,
                     text=word,
                     score=1.0,
                 )
 
         # Create a page transcription on page 1
         p1_1.transcriptions.create(
-            source=recognizer_source,
+            worker_version=recognizer_worker,
             text='Lorem ipsum dolor sit amet',
             score=1.0,
         )
@@ -328,47 +353,3 @@ class Command(BaseCommand):
         sd.add_parent(act3)
         se.add_parent(act4)
         sf.add_parent(act5)
-
-        # Create a worker repository
-        worker_repo = creds.repos.create(
-            type=RepositoryType.Worker,
-            url="http://my_repo.fake/workers/worker",
-            hook_token='worker-hook-token',
-            provider_name='GitLabProvider'
-        )
-
-        # Create a revision on this repository
-        revision = worker_repo.revisions.create(
-            hash="1337",
-            message="My w0rk3r",
-            author="Test user"
-        )
-
-        # Create a fake docker build with a docker image task
-        workflow = Workflow.objects.create(recipe='tasks:\n docker_build:\n  image: reco')
-        build_task = workflow.tasks.create(run=0, depth=0, slug='docker_build', state=State.Completed)
-        docker_image = build_task.artifacts.create(size=42_000, path='/path/to/docker_build')
-
-        # Create two workers for the repository with their available version
-        WorkerVersion.objects.create(
-            worker=worker_repo.workers.create(
-                name='Recognizer',
-                slug='reco',
-                type='recognizer'
-            ),
-            revision=revision,
-            configuration={'test': 42},
-            state=WorkerVersionState.Available,
-            docker_image=docker_image
-        )
-        WorkerVersion.objects.create(
-            worker=worker_repo.workers.create(
-                name='Document layout analyser',
-                slug='dla',
-                type='dla'
-            ),
-            revision=revision,
-            configuration={'test': 42},
-            state=WorkerVersionState.Available,
-            docker_image=docker_image
-        )
diff --git a/arkindex/documents/migrations/0024_drop_datasource.py b/arkindex/documents/migrations/0024_drop_datasource.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe370ef6e4ea7ad87588b136e8f4a4efb8b9c901
--- /dev/null
+++ b/arkindex/documents/migrations/0024_drop_datasource.py
@@ -0,0 +1,64 @@
+# Generated by Django 3.1.3 on 2020-11-30 10:40
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('documents', '0023_remove_transcription_type'),
+    ]
+
+    operations = [
+        migrations.AlterUniqueTogether(
+            name='datasource',
+            unique_together=None,
+        ),
+        migrations.RemoveConstraint(
+            model_name='classification',
+            name='classification_unique_manual',
+        ),
+        migrations.RemoveConstraint(
+            model_name='classification',
+            name='classification_unique_worker_version',
+        ),
+        migrations.RemoveConstraint(
+            model_name='transcription',
+            name='transcription_source_not_worker_version',
+        ),
+        migrations.RemoveField(
+            model_name='classification',
+            name='source',
+        ),
+        migrations.RemoveField(
+            model_name='element',
+            name='source',
+        ),
+        migrations.RemoveField(
+            model_name='entity',
+            name='source',
+        ),
+        migrations.RemoveField(
+            model_name='transcription',
+            name='source',
+        ),
+        migrations.AddConstraint(
+            model_name='classification',
+            constraint=models.UniqueConstraint(
+                condition=models.Q(worker_version_id__isnull=True),
+                fields=('element', 'ml_class'),
+                name='classification_unique_manual'
+            ),
+        ),
+        migrations.AddConstraint(
+            model_name='classification',
+            constraint=models.UniqueConstraint(
+                condition=models.Q(worker_version_id__isnull=False),
+                fields=('element', 'ml_class', 'worker_version'),
+                name='classification_unique_worker_version',
+            ),
+        ),
+        migrations.DeleteModel(
+            name='DataSource',
+        ),
+    ]
diff --git a/arkindex/documents/models.py b/arkindex/documents/models.py
index 599cf9e21953aeec88fdf86d92cbe5ac79edee5e..2f9e3cd5c166199526dbe32c36614e60e713de9f 100644
--- a/arkindex/documents/models.py
+++ b/arkindex/documents/models.py
@@ -19,7 +19,6 @@ from arkindex.project.elastic import ESElement, ESEntity, ESTranscription
 from arkindex.project.fields import ArrayField
 from arkindex.project.models import IndexableModel
 from arkindex_common.enums import EntityType, MetaType
-from arkindex_common.ml_tool import MLToolType
 
 logger = logging.getLogger(__name__)
 
@@ -148,13 +147,6 @@ class Element(IndexableModel):
         null=True,
         blank=True,
     )
-    source = models.ForeignKey(
-        'documents.DataSource',
-        on_delete=models.SET_NULL,
-        related_name='elements',
-        null=True,
-        blank=True,
-    )
     worker_version = models.ForeignKey(
         'dataimport.WorkerVersion',
         on_delete=models.SET_NULL,
@@ -302,23 +294,6 @@ class Element(IndexableModel):
         return '{}: {}'.format(self.type.display_name, self.name)
 
 
-class DataSource(models.Model):
-    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
-    type = EnumField(MLToolType, max_length=50)
-    slug = models.CharField(max_length=100)
-    name = models.CharField(max_length=100)
-    revision = models.CharField(max_length=100)
-    internal = models.BooleanField()
-
-    class Meta:
-        unique_together = (
-            ('type', 'slug', 'revision'),
-        )
-
-    def __str__(self):
-        return '{} {}'.format(self.slug, self.revision)
-
-
 class Entity(InterpretedDateMixin, models.Model):
     """
     Semantic object in arkindex
@@ -338,13 +313,6 @@ class Entity(InterpretedDateMixin, models.Model):
         null=True,
         blank=True
     )
-    source = models.ForeignKey(
-        DataSource,
-        on_delete=models.CASCADE,
-        related_name='entities',
-        null=True,
-        blank=True,
-    )
     worker_version = models.ForeignKey(
         'dataimport.WorkerVersion',
         on_delete=models.CASCADE,
@@ -436,13 +404,6 @@ class Transcription(models.Model):
         on_delete=models.CASCADE,
         related_name='transcriptions',
     )
-    source = models.ForeignKey(
-        DataSource,
-        on_delete=models.CASCADE,
-        related_name='transcriptions',
-        null=True,
-        blank=True,
-    )
     worker_version = models.ForeignKey(
         'dataimport.WorkerVersion',
         on_delete=models.CASCADE,
@@ -461,15 +422,6 @@ class Transcription(models.Model):
     def __str__(self):
         return 'Transcription: {}'.format(self.text[:20])
 
-    class Meta:
-        constraints = [
-            # Require either a source, a worker version, or none (manual), but not both at once
-            models.CheckConstraint(
-                check=~Q(source_id__isnull=False, worker_version_id__isnull=False),
-                name='transcription_source_not_worker_version',
-            )
-        ]
-
 
 class TranscriptionEntity(models.Model):
     """
@@ -536,13 +488,6 @@ class Classification(models.Model):
         on_delete=models.CASCADE,
         related_name='classifications',
     )
-    source = models.ForeignKey(
-        DataSource,
-        on_delete=models.CASCADE,
-        related_name='classifications',
-        null=True,
-        blank=True,
-    )
     worker_version = models.ForeignKey(
         'dataimport.WorkerVersion',
         on_delete=models.CASCADE,
@@ -573,12 +518,12 @@ class Classification(models.Model):
             models.UniqueConstraint(
                 fields=['element', 'ml_class'],
                 name='classification_unique_manual',
-                condition=Q(worker_version_id__isnull=True, source_id__isnull=True),
+                condition=Q(worker_version_id__isnull=True),
             ),
             models.UniqueConstraint(
                 fields=['element', 'ml_class', 'worker_version'],
                 name='classification_unique_worker_version',
-                condition=Q(worker_version_id__isnull=False, source_id__isnull=True),
+                condition=Q(worker_version_id__isnull=False),
             )
         ]
 
diff --git a/arkindex/documents/search.py b/arkindex/documents/search.py
index b96cb85edc327fab13e537bbce93453de867e1c7..a905f2dabc78509d4a03dbbb291577a0e9b59212 100644
--- a/arkindex/documents/search.py
+++ b/arkindex/documents/search.py
@@ -15,7 +15,7 @@ def search_transcriptions_post(data):
     ts = Transcription.objects \
                       .filter(id__in=transcription_ids) \
                       .order_by('-score') \
-                      .prefetch_related('element__zone__image__server', 'source')
+                      .select_related('element__zone__image__server', 'worker_version')
     element_ids = list(ts.values_list('element_id', flat=True))
     all_parent_paths = Element.objects.get_ascendings_paths(*element_ids)
     for trans in ts:
@@ -65,7 +65,7 @@ def search_elements_post(data):
 
     transcriptions = {
         t.id: t
-        for t in Transcription.objects.filter(id__in=tr_ids).prefetch_related('source')
+        for t in Transcription.objects.filter(id__in=tr_ids).select_related('worker_version')
     }
 
     elts_tr_ids = {
diff --git a/arkindex/documents/serializers/elements.py b/arkindex/documents/serializers/elements.py
index 8bb1c056f91627cbac114f3831b070b7bde39d82..72fbc050065bb3ae9032e5e71d206a5d9c9f7447 100644
--- a/arkindex/documents/serializers/elements.py
+++ b/arkindex/documents/serializers/elements.py
@@ -24,7 +24,7 @@ from arkindex.documents.serializers.light import (
     ElementTypeLightSerializer,
     MetaDataLightSerializer,
 )
-from arkindex.documents.serializers.ml import ClassificationSerializer, DataSourceSerializer
+from arkindex.documents.serializers.ml import ClassificationSerializer
 from arkindex.images.models import Image, Zone
 from arkindex.images.serializers import ZoneSerializer
 from arkindex.project.serializer_fields import LinearRingField
@@ -257,7 +257,6 @@ class ElementSerializer(ElementSlimSerializer):
         help_text='Set the polygon linking this element to the image. '
                   '`image` must be set when this field is set and there was no image or polygon defined before.',
     )
-    source = DataSourceSerializer(read_only=True, required=False)
 
     class Meta:
         model = Element
@@ -266,13 +265,11 @@ class ElementSerializer(ElementSlimSerializer):
             'classifications',
             'image',
             'polygon',
-            'source',
             'worker_version'
         )
         read_only_fields = ElementSlimSerializer.Meta.read_only_fields + (
             'metadata',
             'classifications',
-            'source',
             'worker_version'
         )
 
diff --git a/arkindex/documents/serializers/entities.py b/arkindex/documents/serializers/entities.py
index 8deca6f31a77e086a55011faa5bc15ebeb6223e5..932cdf7550c6f6168fd4742d640d2d77b9b98b5d 100644
--- a/arkindex/documents/serializers/entities.py
+++ b/arkindex/documents/serializers/entities.py
@@ -3,7 +3,6 @@ from rest_framework import serializers
 from arkindex.dataimport.models import WorkerVersion
 from arkindex.documents.models import Corpus, Entity, EntityLink, EntityRole, TranscriptionEntity
 from arkindex.documents.serializers.light import CorpusLightSerializer, InterpretedDateSerializer
-from arkindex.documents.serializers.ml import DataSourceSerializer
 from arkindex.project.serializer_fields import EnumField
 from arkindex.project.triggers import reindex_start
 from arkindex_common.enums import EntityType
@@ -16,7 +15,6 @@ class BaseEntitySerializer(serializers.ModelSerializer):
     type = EnumField(EntityType)
     dates = InterpretedDateSerializer(many=True, source='get_dates', read_only=True)
     metas = serializers.HStoreField(child=serializers.CharField(), required=False, allow_null=True)
-    source = DataSourceSerializer(read_only=True)
     worker_version_id = serializers.PrimaryKeyRelatedField(read_only=True)
 
     class Meta:
@@ -28,13 +26,11 @@ class BaseEntitySerializer(serializers.ModelSerializer):
             'metas',
             'validated',
             'dates',
-            'source',
             'worker_version_id',
         )
         read_only_fields = (
             'id',
             'dates',
-            'source',
             'worker_version_id',
         )
 
diff --git a/arkindex/documents/serializers/ml.py b/arkindex/documents/serializers/ml.py
index d3e4326665eed211aa5d3c60e13d33090cda4097..dfabfdac86eb68491f8da582ca49476626c609ac 100644
--- a/arkindex/documents/serializers/ml.py
+++ b/arkindex/documents/serializers/ml.py
@@ -11,7 +11,6 @@ from arkindex.documents.models import (
     Classification,
     ClassificationState,
     Corpus,
-    DataSource,
     Element,
     ElementType,
     MLClass,
@@ -19,7 +18,6 @@ from arkindex.documents.models import (
 )
 from arkindex.documents.serializers.light import ElementZoneSerializer
 from arkindex.project.serializer_fields import EnumField, LinearRingField
-from arkindex_common.ml_tool import MLToolType
 
 
 class ClassificationMode(Enum):
@@ -30,41 +28,6 @@ class ClassificationMode(Enum):
     Create = "create"
 
 
-class DataSourceSerializer(serializers.ModelSerializer):
-    """
-    Serialize a data source for transcriptions and classifications
-    """
-
-    type = EnumField(MLToolType)
-
-    class Meta:
-        model = DataSource
-        fields = (
-            'id',
-            'type',
-            'slug',
-            'name',
-            'revision',
-            'internal',
-        )
-
-
-class DataSourceStatsSerializer(DataSourceSerializer):
-    """
-    A data source, but including their result counts
-    """
-    classifications_count = serializers.IntegerField(default=0)
-    transcriptions_count = serializers.IntegerField(default=0)
-    entities_count = serializers.IntegerField(default=0)
-
-    class Meta(DataSourceSerializer.Meta):
-        fields = DataSourceSerializer.Meta.fields + (
-            'classifications_count',
-            'transcriptions_count',
-            'entities_count',
-        )
-
-
 class MLClassSerializer(serializers.ModelSerializer):
     """
     Serializer for MLClass instances
@@ -98,7 +61,6 @@ class ClassificationSerializer(serializers.ModelSerializer):
     Serialize a classification on an Element
     """
 
-    source = DataSourceSerializer()
     ml_class = MLClassSerializer()
     state = EnumField(ClassificationState)
 
@@ -107,7 +69,6 @@ class ClassificationSerializer(serializers.ModelSerializer):
         read_only_fields = ('id', 'confidence', 'high_confidence')
         fields = (
             'id',
-            'source',
             'ml_class',
             'state',
             'confidence',
@@ -153,11 +114,11 @@ class ClassificationCreateSerializer(serializers.ModelSerializer):
         read_only_fields = ('id', 'state')
         validators = [
             UniqueTogetherValidator(
-                queryset=Classification.objects.using('default').filter(worker_version__isnull=False, source_id__isnull=True),
+                queryset=Classification.objects.using('default').filter(worker_version__isnull=False),
                 fields=['element', 'worker_version', 'ml_class']
             ),
             UniqueTogetherValidator(
-                queryset=Classification.objects.using('default').filter(worker_version__isnull=True, source_id__isnull=True),
+                queryset=Classification.objects.using('default').filter(worker_version__isnull=True),
                 fields=['element', 'ml_class']
             )
         ]
@@ -239,18 +200,16 @@ class ClassificationsSelectionSerializer(serializers.ModelSerializer):
 
 class TranscriptionSerializer(serializers.ModelSerializer):
     """
-    Serialises a Transcription
+    Serializes a Transcription
     """
-    source = DataSourceSerializer(read_only=True)
 
     class Meta:
         model = Transcription
-        read_only_fields = ('id', 'score', 'source')
+        read_only_fields = ('id', 'score')
         fields = (
             'id',
             'text',
             'score',
-            'source',
             'worker_version_id',
         )
 
diff --git a/arkindex/documents/tasks.py b/arkindex/documents/tasks.py
index 599cb6af67b87baad9fed0f601e38d936c6ec4dc..064afbb36a682bd44ee16c61aac9935382571f34 100644
--- a/arkindex/documents/tasks.py
+++ b/arkindex/documents/tasks.py
@@ -1,9 +1,7 @@
 import logging
-from math import ceil
 from typing import Optional
 
 from django.db.models import Q
-from django.db.models.deletion import Collector
 from django_rq import job
 from rq import get_current_job
 
@@ -26,37 +24,6 @@ from arkindex.documents.models import (
 logger = logging.getLogger(__name__)
 
 
-def _delete_queryset(queryset, batch_size=1000):
-    """
-    Helper to delete large querysets with as little SQL queries and memory footprint as possible.
-    """
-    count = queryset.count()
-    logger.info('Deleting {} {}'.format(count, queryset.model.__name__))
-
-    if not count:
-        return
-
-    if Collector(using=queryset.db).can_fast_delete(queryset.all()):
-        # If a single DELETE statement can be used,
-        # bypass both the batched deletion and Django's related objects checks.
-        logger.debug('Using single-query deletion')
-        queryset._raw_delete(using=queryset.db)
-        return
-
-    if count <= batch_size:
-        # If there is a single batch, just delete.
-        queryset.delete()
-        return
-
-    for i in range(ceil(count / batch_size)):
-        logger.debug('Deleting batch {}'.format(i + 1))
-        # Deleting a slice is not allowed;
-        # we use a sliced subquery instead and still delete in a single query.
-        # DELETE FROM … WHERE id IN (SELECT id FROM … LIMIT [batch_size])
-        ids = queryset[:batch_size].values('id')
-        queryset.model.objects.filter(id__in=ids).delete()
-
-
 @job
 def reindex_start(corpus_id: Optional[str] = None,
                   element_id: Optional[str] = None,
@@ -110,51 +77,6 @@ def reindex_start(corpus_id: Optional[str] = None,
         indexer.run_index(entities_queryset, bulk_size=400)
 
 
-@job('high')
-def ml_results_delete(corpus_id: Optional[str] = None,
-                      element_id: Optional[str] = None,
-                      batch_size: int = 1000) -> None:
-    assert corpus_id or element_id, 'Missing element or corpus IDs'
-
-    if element_id:
-        logger.info('Deleting ML results on element {}'.format(element_id))
-        element = Element.objects.get(id=element_id)
-        if element.type.folder:
-            # The folder AND its children
-            elements = Element.objects.filter(id=element_id).values('id').union(
-                # Disable ordering here because we do not need it and it adds an extra column,
-                # causing the UNION to fail
-                Element.objects.get_descending(element_id).order_by().values('id')
-            )
-        else:
-            elements = [element]
-
-        if not corpus_id:
-            # The corpus ID is still used in some deletions; deduce it from the element.
-            corpus_id = Element.objects.get(id=element_id).corpus_id
-    elif corpus_id:
-        logger.info('Deleting ML results on corpus {}'.format(corpus_id))
-        elements = Element.objects.filter(corpus_id=corpus_id)
-
-    # Simple deletions for classifications and transcriptions.
-    _delete_queryset(Classification.objects.filter(element__in=elements).exclude(source__slug='manual'), batch_size)
-    _delete_queryset(Transcription.objects.filter(element__in=elements).exclude(source__slug='manual'), batch_size)
-
-    # Entity deletion is complex: they can be linked to different elements both on transcriptions and metadata.
-    # Metadata are not considered ML results so we need to keep them: update them to unlink entities.
-    logger.info('Updating element metadata')
-    MetaData.objects.filter(element__in=elements).update(entity_id=None)
-
-    # We removed transcriptions earlier, which implies removing the links with entities.
-    # All is left is to remove 'lonely' entities.
-    # Note: __isnull's implementation will fetch all element IDs into a list before deleting—use batches!
-    _delete_queryset(Entity.objects.filter(
-        corpus_id=corpus_id,
-        metadatas__isnull=True,
-        transcriptions__isnull=True,
-    ), batch_size)
-
-
 @job('high')
 def corpus_delete(corpus_id: str) -> None:
     # Note that this can be None when the task is run outside of a RQ worker (e.g. unit test)
diff --git a/arkindex/documents/tests/commands/test_reindex.py b/arkindex/documents/tests/commands/test_reindex.py
index 0531056f530328711ffc2904d8ae94c9a07ec4de..ff2d90d73e49745d10b8872ebda08c411cfd5daa 100644
--- a/arkindex/documents/tests/commands/test_reindex.py
+++ b/arkindex/documents/tests/commands/test_reindex.py
@@ -3,7 +3,8 @@ from unittest.mock import call, patch
 from django.core.management import CommandError, call_command
 from django.test import override_settings
 
-from arkindex.documents.models import DataSource, Element, Entity, EntityType, MLToolType, Transcription
+from arkindex.dataimport.models import WorkerVersion
+from arkindex.documents.models import Element, Entity, EntityType, Transcription
 from arkindex.project.elastic import ESElement, ESEntity, ESTranscription
 from arkindex.project.tests import FixtureTestCase
 from arkindex_common.enums import MetaType
@@ -14,10 +15,10 @@ class TestReindexCommand(FixtureTestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        source = DataSource.objects.create(type=MLToolType.NER, slug='entity', internal=True)
         cls.indexer_patch = patch('arkindex.documents.management.commands.reindex.Indexer')
         cls.vol = cls.corpus.elements.get(name="Volume 1")
-        cls.entity = cls.corpus.entities.create(type=EntityType.Misc, name='Dummy entity', source=source)
+        worker_version = WorkerVersion.objects.first()
+        cls.entity = cls.corpus.entities.create(type=EntityType.Misc, name='Dummy entity', worker_version=worker_version)
         page = cls.corpus.elements.get(name='Volume 1, page 1r')
         page.metadatas.create(name='Dummy metadata', value='Dummy', type=MetaType.Text, entity=cls.entity)
 
diff --git a/arkindex/documents/tests/tasks/test_corpus_delete.py b/arkindex/documents/tests/tasks/test_corpus_delete.py
index 53c2cd99c50b31d7d7756a43ef960acd56e699f3..db15d2c640ca964f2ef648e1087f8c50842d15c9 100644
--- a/arkindex/documents/tests/tasks/test_corpus_delete.py
+++ b/arkindex/documents/tests/tasks/test_corpus_delete.py
@@ -1,11 +1,10 @@
 from django.db.models.signals import pre_delete
 
 from arkindex.dataimport.models import Repository, RepositoryType, WorkerVersion
-from arkindex.documents.models import Corpus, DataSource, Element, Transcription
+from arkindex.documents.models import Corpus, Element, Transcription
 from arkindex.documents.tasks import corpus_delete
 from arkindex.project.tests import FixtureTestCase
 from arkindex_common.enums import DataImportMode, EntityType, MetaType
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestDeleteCorpus(FixtureTestCase):
@@ -32,12 +31,14 @@ class TestDeleteCorpus(FixtureTestCase):
         )
         file_import.build_workflow()
 
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
+
         element_import = cls.corpus.imports.create(
             creator=cls.user,
             mode=DataImportMode.Workers,
         )
         element_import.elements.add(element)
-        element_import.worker_runs.create(version=WorkerVersion.objects.first(), parents=[])
+        element_import.worker_runs.create(version=cls.worker_version, parents=[])
 
         entity1 = cls.corpus.entities.create(name='Magnemite', type=EntityType.Person)
         entity2 = cls.corpus.entities.create(name='Magneton', type=EntityType.Person)
@@ -98,24 +99,14 @@ class TestDeleteCorpus(FixtureTestCase):
             name='A page',
         )
         cls.page.classifications.create(
-            source=DataSource.objects.create(
-                type=MLToolType.Classifier,
-                slug='classeur',
-                revision='Early Access',
-                internal=False,
-            ),
+            worker_version=cls.worker_version,
             ml_class=cls.corpus2.ml_classes.create(
                 name='klass',
             ),
             confidence=0.5,
         )
         cls.page.transcriptions.create(
-            source=DataSource.objects.create(
-                type=MLToolType.Recognizer,
-                slug='reco',
-                revision='-1',
-                internal=False,
-            ),
+            worker_version=cls.worker_version,
             text='hi',
             score=0.75,
         )
@@ -159,11 +150,11 @@ class TestDeleteCorpus(FixtureTestCase):
         self.assertEqual(md.value, 'data')
 
         cl = self.page.classifications.get()
-        self.assertEqual(cl.source.slug, 'classeur')
+        self.assertEqual(cl.worker_version, self.worker_version)
         self.assertEqual(cl.ml_class.name, 'klass')
         self.assertEqual(cl.confidence, 0.5)
 
         ts = self.page.transcriptions.get()
-        self.assertEqual(ts.source.slug, 'reco')
+        self.assertEqual(ts.worker_version, self.worker_version)
         self.assertEqual(ts.text, 'hi')
         self.assertEqual(ts.score, 0.75)
diff --git a/arkindex/documents/tests/tasks/test_ml_results_delete.py b/arkindex/documents/tests/tasks/test_ml_results_delete.py
deleted file mode 100644
index 0c7a8b57cea3d8ece46007df1024685a358bc214..0000000000000000000000000000000000000000
--- a/arkindex/documents/tests/tasks/test_ml_results_delete.py
+++ /dev/null
@@ -1,169 +0,0 @@
-from arkindex.documents.models import Classification, DataSource, Element, Entity, Transcription
-from arkindex.documents.tasks import ml_results_delete
-from arkindex.project.tests import FixtureTestCase
-from arkindex_common.enums import EntityType, MetaType
-from arkindex_common.ml_tool import MLToolType
-
-
-class TestMLResultsDelete(FixtureTestCase):
-
-    @classmethod
-    def setUpTestData(cls):
-        super().setUpTestData()
-        cls.folder1 = cls.corpus.elements.get(name='Volume 1')
-        cls.folder2 = cls.corpus.elements.get(name='Volume 2')
-
-        source = DataSource.objects.get(slug='test', type=MLToolType.Recognizer)
-        ml_class = cls.corpus.ml_classes.create(name='Some class')
-
-        cls.page1 = cls.corpus.elements.get(name='Volume 1, page 1r')
-        cls.page1.classifications.create(
-            ml_class=ml_class,
-            confidence=0.42,
-            source=source,
-        )
-        entity1 = cls.corpus.entities.create(
-            type=EntityType.Person,
-            name='Some entity 1',
-            source=source,
-        )
-        cls.page1.metadatas.create(
-            type=MetaType.Text,
-            name='something',
-            value='Some entity 1',
-            entity=entity1,
-        )
-        cls.page1.transcriptions.first().transcription_entities.create(
-            offset=0,
-            length=1,
-            entity=entity1,
-        )
-
-        cls.page2 = cls.corpus.elements.get(name='Volume 2, page 1r')
-        cls.page2.classifications.create(
-            ml_class=ml_class,
-            confidence=0.42,
-            source=source,
-        )
-        entity2 = cls.corpus.entities.create(
-            type=EntityType.Person,
-            name='Some entity 2',
-            source=source,
-        )
-        cls.page2.metadatas.create(
-            type=MetaType.Text,
-            name='something',
-            value='Some entity 2',
-            entity=entity2,
-        )
-        cls.page2.transcriptions.create(
-            score=0.74,
-            text='some text',
-            source=source,
-        ).transcription_entities.create(
-            offset=0,
-            length=1,
-            entity=entity2,
-        )
-
-    def _get_querysets(self, elements):
-        return [
-            Transcription.objects.filter(element__in=elements),
-            Entity.objects.filter(transcriptions__element__in=elements),
-            Entity.objects.filter(metadatas__element__in=elements),
-            Classification.objects.filter(element__in=elements),
-        ]
-
-    def test_delete_missing_parameters(self):
-        with self.assertRaises(AssertionError):
-            ml_results_delete()
-
-    def test_delete_corpus(self):
-        querysets = self._get_querysets(self.corpus.elements.all())
-
-        for queryset in querysets:
-            self.assertTrue(queryset.exists())
-
-        self.assertEqual(self.page1.metadatas.count(), 2)
-        self.assertEqual(self.page2.metadatas.count(), 2)
-
-        with self.assertNumQueries(13):
-            ml_results_delete(corpus_id=self.corpus.id)
-
-        for queryset in querysets:
-            self.assertFalse(queryset.exists())
-
-        self.assertEqual(self.page1.metadatas.count(), 2)
-        self.assertEqual(self.page2.metadatas.count(), 2)
-        metadata = self.page1.metadatas.get(value='Some entity 1')
-        self.assertEqual(metadata.type, MetaType.Text)
-        self.assertIsNone(metadata.entity)
-        metadata = self.page2.metadatas.get(value='Some entity 2')
-        self.assertEqual(metadata.type, MetaType.Text)
-        self.assertIsNone(metadata.entity)
-
-    def test_delete_folder(self):
-        folder1_querysets = self._get_querysets(
-            Element.objects.filter(id=self.folder1.id).values('id').union(
-                Element.objects.get_descending(self.folder1.id).order_by().values('id')
-            )
-        )
-        folder2_querysets = self._get_querysets(
-            Element.objects.filter(id=self.folder2.id).values('id').union(
-                Element.objects.get_descending(self.folder2.id).order_by().values('id')
-            )
-        )
-
-        for queryset in folder1_querysets:
-            self.assertTrue(queryset.exists())
-        for queryset in folder2_querysets:
-            self.assertTrue(queryset.exists())
-
-        with self.assertNumQueries(16):
-            ml_results_delete(element_id=self.folder1.id)
-
-        for queryset in folder1_querysets:
-            self.assertFalse(queryset.exists())
-        for queryset in folder2_querysets:  # This folder should not change
-            self.assertTrue(queryset.exists())
-
-        self.assertEqual(self.page1.metadatas.count(), 2)
-        self.assertEqual(self.page2.metadatas.count(), 2)
-        metadata = self.page1.metadatas.get(value='Some entity 1')
-        self.assertEqual(metadata.type, MetaType.Text)
-        self.assertIsNone(metadata.entity)
-        metadata = self.page2.metadatas.get(value='Some entity 2')
-        self.assertEqual(metadata.type, MetaType.Text)
-        self.assertIsNotNone(metadata.entity)
-
-    def test_delete_page(self):
-        page1_querysets = self._get_querysets(
-            Element.objects.filter(id=self.page1.id).values('id')
-        )
-        folder2_querysets = self._get_querysets(
-            Element.objects.filter(id=self.folder2.id).values('id').union(
-                Element.objects.get_descending(self.folder2.id).order_by().values('id')
-            )
-        )
-
-        for queryset in page1_querysets:
-            self.assertTrue(queryset.exists())
-        for queryset in folder2_querysets:
-            self.assertTrue(queryset.exists())
-
-        with self.assertNumQueries(16):
-            ml_results_delete(element_id=self.page1.id)
-
-        for queryset in page1_querysets:
-            self.assertFalse(queryset.exists())
-        for queryset in folder2_querysets:  # This folder should not change
-            self.assertTrue(queryset.exists())
-
-        self.assertEqual(self.page1.metadatas.count(), 2)
-        self.assertEqual(self.page2.metadatas.count(), 2)
-        metadata = self.page1.metadatas.get(value='Some entity 1')
-        self.assertEqual(metadata.type, MetaType.Text)
-        self.assertIsNone(metadata.entity)
-        metadata = self.page2.metadatas.get(value='Some entity 2')
-        self.assertEqual(metadata.type, MetaType.Text)
-        self.assertIsNotNone(metadata.entity)
diff --git a/arkindex/documents/tests/tasks/test_reindex.py b/arkindex/documents/tests/tasks/test_reindex.py
index 014d09795eca1596ee9ce89229af961eafc3ce7e..0f5f3fccfe045e1b3b11ce83638e62302c20f3df 100644
--- a/arkindex/documents/tests/tasks/test_reindex.py
+++ b/arkindex/documents/tests/tasks/test_reindex.py
@@ -3,11 +3,11 @@ from unittest.mock import patch
 from django.contrib.gis.geos import LinearRing
 from django.db.models import Q
 
-from arkindex.documents.models import Corpus, DataSource, Element, Entity, Transcription
+from arkindex.dataimport.models import WorkerVersion
+from arkindex.documents.models import Corpus, Element, Entity, Transcription
 from arkindex.documents.tasks import reindex_start
 from arkindex.project.tests import FixtureTestCase
 from arkindex_common.enums import EntityType, MetaType
-from arkindex_common.ml_tool import MLToolType
 
 
 @patch('arkindex.documents.tasks.Indexer')
@@ -16,8 +16,7 @@ class TestReindex(FixtureTestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        source = DataSource.objects.get(slug='test', type=MLToolType.Recognizer)
-
+        cls.worker_version = WorkerVersion.objects.first()
         cls.folder = cls.corpus.elements.get(name='Volume 1')
         cls.folder.metadatas.create(
             type=MetaType.Text,
@@ -26,7 +25,7 @@ class TestReindex(FixtureTestCase):
             entity=cls.corpus.entities.create(
                 type=EntityType.Person,
                 name='Some entity',
-                source=source,
+                worker_version=cls.worker_version,
             )
         )
 
@@ -41,13 +40,13 @@ class TestReindex(FixtureTestCase):
         ts = element2.transcriptions.create(
             score=0.8,
             text='something',
-            source=source,
+            worker_version=cls.worker_version,
         )
         ts.transcription_entities.create(
             entity=corpus2.entities.create(
                 type=EntityType.Misc,
                 name='Some other entity',
-                source=source,
+                worker_version=cls.worker_version,
             ),
             offset=0,
             length=1,
diff --git a/arkindex/documents/tests/test_bulk_classification.py b/arkindex/documents/tests/test_bulk_classification.py
index 1ab1261240e0640884bf469c3fea29b11c3439f0..e834fe55d91d354907336f30868dbcf0c0f4ec7d 100644
--- a/arkindex/documents/tests/test_bulk_classification.py
+++ b/arkindex/documents/tests/test_bulk_classification.py
@@ -2,9 +2,8 @@ from django.urls import reverse
 from rest_framework import status
 
 from arkindex.dataimport.models import WorkerVersion
-from arkindex.documents.models import Corpus, DataSource, MLClass
+from arkindex.documents.models import Corpus, MLClass
 from arkindex.project.tests import FixtureAPITestCase
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestBulkClassification(FixtureAPITestCase):
@@ -13,22 +12,9 @@ class TestBulkClassification(FixtureAPITestCase):
     def setUpTestData(cls):
         super().setUpTestData()
         cls.page = cls.corpus.elements.get(name='Volume 1, page 2r')
-        cls.src = DataSource.objects.get(slug='test', type=MLToolType.Classifier)
         cls.private_corpus = Corpus.objects.create(name='private', public=False)
         cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
 
-    @classmethod
-    def setUpClass(cls):
-        super().setUpClass()
-        cls.src.internal = True
-        cls.src.save()
-
-    @classmethod
-    def tearDownClass(cls):
-        super().tearDownClass()
-        cls.src.internal = False
-        cls.src.save()
-
     def create_classifications_data(self, classifications, parent=None):
         return {
             "parent": parent or str(self.page.id),
@@ -90,12 +76,11 @@ class TestBulkClassification(FixtureAPITestCase):
                 'ml_class__name',
                 'confidence',
                 'high_confidence',
-                'source',
                 'worker_version'
             )),
             [
-                ('dog', 0.99, True, None, self.worker_version.id),
-                ('cat', 0.42, False, None, self.worker_version.id)
+                ('dog', 0.99, True, self.worker_version.id),
+                ('cat', 0.42, False, self.worker_version.id)
             ],
         )
 
diff --git a/arkindex/documents/tests/test_bulk_element_transcriptions.py b/arkindex/documents/tests/test_bulk_element_transcriptions.py
index b07e965e4d12c35c350e8949a1432f1619b00c89..71a2abb020dab77e49d5d8bb97e6e28173a13ced 100644
--- a/arkindex/documents/tests/test_bulk_element_transcriptions.py
+++ b/arkindex/documents/tests/test_bulk_element_transcriptions.py
@@ -75,10 +75,10 @@ class TestBulkElementTranscriptions(FixtureAPITestCase):
             ]
         )
         self.assertCountEqual(
-            created_elts.values_list('transcriptions__text', 'transcriptions__source', 'transcriptions__worker_version'),
+            created_elts.values_list('transcriptions__text', 'transcriptions__worker_version'),
             [
-                ('Hello world !', None, self.worker_version.id),
-                ('I <3 JavaScript', None, self.worker_version.id)
+                ('Hello world !', self.worker_version.id),
+                ('I <3 JavaScript', self.worker_version.id)
             ]
         )
         self.assertEqual(delay_mock.call_count, 1)
@@ -359,10 +359,10 @@ class TestBulkElementTranscriptions(FixtureAPITestCase):
             ]
         )
         self.assertCountEqual(
-            created_elts.values_list('transcriptions__text', 'transcriptions__source', 'transcriptions__worker_version'),
+            created_elts.values_list('transcriptions__text', 'transcriptions__worker_version'),
             [
-                ('Hello world !', None, self.worker_version.id),
-                ('I <3 JavaScript', None, self.worker_version.id)
+                ('Hello world !', self.worker_version.id),
+                ('I <3 JavaScript', self.worker_version.id)
             ]
         )
         self.assertEqual(delay_mock.call_count, 1)
diff --git a/arkindex/documents/tests/test_classes.py b/arkindex/documents/tests/test_classes.py
index 9f6bfa282a084bab37d64e303e9e864a54db1df6..8b731dc2a399d4385fa440236f6cd2e0f49547ee 100644
--- a/arkindex/documents/tests/test_classes.py
+++ b/arkindex/documents/tests/test_classes.py
@@ -2,9 +2,9 @@ from django.test import override_settings
 from django.urls import reverse
 from rest_framework import status
 
-from arkindex.documents.models import Classification, ClassificationState, Corpus, DataSource, Element, MLClass
+from arkindex.dataimport.models import WorkerVersion
+from arkindex.documents.models import Classification, ClassificationState, Corpus, Element, MLClass
 from arkindex.project.tests import FixtureAPITestCase
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestClasses(FixtureAPITestCase):
@@ -21,14 +21,8 @@ class TestClasses(FixtureAPITestCase):
         self.parent = self.corpus.elements.create(type=self.folder_type)
         self.common_children = self.corpus.elements.create(type=self.folder_type)
 
-        source1 = DataSource.objects.get(slug='test', type=MLToolType.Recognizer)
-        source2 = DataSource.objects.create(
-            type=MLToolType.Classifier,
-            slug='source2',
-            name='classifier',
-            revision='123',
-            internal=False,
-        )
+        self.version1 = WorkerVersion.objects.get(worker__slug='reco')
+        self.version2 = WorkerVersion.objects.get(worker__slug='dla')
         for elt_num in range(1, 13):
             elt = Element.objects.create(
                 name='elt_{}'.format(elt_num),
@@ -38,9 +32,9 @@ class TestClasses(FixtureAPITestCase):
             elt.add_parent(self.parent)
             self.common_children.add_parent(elt)
             for ml_class, score in zip((self.text, self.cover), (.7, .99)):
-                for source in (source1, source2):
+                for worker_version in (self.version1, self.version2):
                     elt.classifications.create(
-                        source_id=source.id,
+                        worker_version=worker_version,
                         ml_class_id=ml_class.id,
                         confidence=score,
                         high_confidence=bool(score == .99)
@@ -245,8 +239,8 @@ class TestClasses(FixtureAPITestCase):
         self.assertEqual(data['count'], 12)
         for elt in data['results']:
             self.assertCountEqual(
-                list(map(lambda c: (c['source']['slug'], c['confidence']), elt['best_classes'])),
-                [('source2', .99), ('test', .99)]
+                list(map(lambda c: (c['worker_version'], c['confidence']), elt['best_classes'])),
+                [(str(self.version1.id), .99), (str(self.version2.id), .99)]
             )
 
     def test_list_elements_best_classes_false(self):
@@ -275,8 +269,8 @@ class TestClasses(FixtureAPITestCase):
         self.assertEqual(data['count'], 12)
         for elt in data['results']:
             self.assertCountEqual(
-                list(map(lambda c: (c['source']['slug'], c['confidence']), elt['best_classes'])),
-                [('source2', .99), ('test', .99)]
+                list(map(lambda c: (c['worker_version'], c['confidence']), elt['best_classes'])),
+                [(str(self.version1.id), .99), (str(self.version2.id), .99)]
             )
 
     def test_element_children_best_classes(self):
@@ -291,8 +285,8 @@ class TestClasses(FixtureAPITestCase):
         self.assertEqual(data['count'], 12)
         for elt in data['results']:
             self.assertCountEqual(
-                list(map(lambda c: (c['source']['slug'], c['confidence']), elt['best_classes'])),
-                [('source2', .99), ('test', .99)]
+                list(map(lambda c: (c['worker_version'], c['confidence']), elt['best_classes'])),
+                [(str(self.version1.id), .99), (str(self.version2.id), .99)]
             )
 
     def test_rejected_best_classes(self):
@@ -330,13 +324,18 @@ class TestClasses(FixtureAPITestCase):
         for elt in response.json()['results']:
             if elt['id'] == str(parent.id):
                 self.assertCountEqual(
-                    list(map(lambda c: (c['source']['slug'], c['confidence']), elt['best_classes'])),
-                    [('source2', .99), ('test', .99), ('source2', .7), ('test', .7)]
+                    list(map(lambda c: (c['worker_version'], c['confidence']), elt['best_classes'])),
+                    [
+                        (str(self.version1.id), .99),
+                        (str(self.version2.id), .99),
+                        (str(self.version1.id), .7),
+                        (str(self.version2.id), .7),
+                    ]
                 )
                 continue
             self.assertCountEqual(
-                list(map(lambda c: (c['source']['slug'], c['confidence']), elt['best_classes'])),
-                [('source2', .99), ('test', .99)]
+                list(map(lambda c: (c['worker_version'], c['confidence']), elt['best_classes'])),
+                [(str(self.version1.id), .99), (str(self.version2.id), .99)]
             )
 
     def test_rejected_human_class(self):
@@ -344,10 +343,8 @@ class TestClasses(FixtureAPITestCase):
         A manual classification rejected by a human may not appear in best classes
         """
         self.populate_classified_elements()
-        data_source, _ = DataSource.objects.get_or_create(type=MLToolType.NER, slug="manual", internal=False)
         element = Element.objects.filter(type=self.classified.id).first()
         classif = element.classifications.create(
-            source_id=data_source.id,
             ml_class_id=self.text.id,
             confidence=1,
             high_confidence=True,
@@ -360,13 +357,20 @@ class TestClasses(FixtureAPITestCase):
         for elt in response.json()['results']:
             if elt['id'] == str(element.id):
                 self.assertCountEqual(
-                    list(map(lambda c: (c['source']['slug'], c['confidence']), elt['best_classes'])),
-                    [('manual', 1.0), ('test', .99), ('source2', .99)]
+                    list(map(lambda c: (c['worker_version'], c['confidence']), elt['best_classes'])),
+                    [
+                        (None, 1.0),
+                        (str(self.version1.id), .99),
+                        (str(self.version2.id), .99),
+                    ]
                 )
                 continue
             self.assertCountEqual(
-                list(map(lambda c: (c['source']['slug'], c['confidence']), elt['best_classes'])),
-                [('source2', .99), ('test', .99)]
+                list(map(lambda c: (c['worker_version'], c['confidence']), elt['best_classes'])),
+                [
+                    (str(self.version1.id), .99),
+                    (str(self.version2.id), .99),
+                ]
             )
         # Reject the manual classification
         classif.state = ClassificationState.Rejected
@@ -378,16 +382,15 @@ class TestClasses(FixtureAPITestCase):
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         for elt in response.json()['results']:
             self.assertCountEqual(
-                list(map(lambda c: (c['source']['slug'], c['confidence']), elt['best_classes'])),
-                [('source2', .99), ('test', .99)]
+                list(map(lambda c: (c['worker_version'], c['confidence']), elt['best_classes'])),
+                [(str(self.version1.id), .99), (str(self.version2.id), .99)]
             )
 
     def test_class_filter_list_elements(self):
         self.populate_classified_elements()
         element = Element.objects.filter(type=self.classified.id).first()
         element.classifications.create(
-            source_id=DataSource.objects.create(type=MLToolType.NER, slug='ner', internal=False).id,
-            ml_class_id=self.text.id,
+            ml_class=self.text,
             confidence=.1337,
             high_confidence=True,
         )
@@ -482,7 +485,7 @@ class TestClasses(FixtureAPITestCase):
         element = Element.objects.filter(type=self.classified.id).first()
         element.classifications.all().delete()
         element.classifications.create(
-            source_id=DataSource.objects.create(type=MLToolType.NER, slug='ner', internal=False).id,
+            worker_version=self.version2,
             ml_class_id=self.text.id,
             confidence=.1337,
             high_confidence=True,
@@ -507,7 +510,7 @@ class TestClasses(FixtureAPITestCase):
         element = Element.objects.filter(type=self.classified.id).first()
         element.classifications.all().delete()
         element.classifications.create(
-            source_id=DataSource.objects.create(type=MLToolType.NER, slug='ner', internal=False).id,
+            worker_version=self.version2,
             ml_class_id=self.text.id,
             confidence=.1337,
             high_confidence=False,
diff --git a/arkindex/documents/tests/test_create_elements.py b/arkindex/documents/tests/test_create_elements.py
index 607bbfbcb5409084bf54fdce845a251593a5c904..5c1423a3b002d36ea3ad8d9f1be7f582c3ce6152 100644
--- a/arkindex/documents/tests/test_create_elements.py
+++ b/arkindex/documents/tests/test_create_elements.py
@@ -65,7 +65,6 @@ class TestCreateElements(FixtureAPITestCase):
                 'type': volume.type.slug,
                 'thumbnail_put_url': None,
                 'thumbnail_url': volume.thumbnail.s3_url,
-                'source': None,
                 'worker_version': None,
                 'classifications': [],
                 'metadata': [],
@@ -104,7 +103,6 @@ class TestCreateElements(FixtureAPITestCase):
                 'type': page.type.slug,
                 'thumbnail_put_url': None,
                 'thumbnail_url': None,
-                'source': None,
                 'worker_version': None,
                 'classifications': [],
                 'metadata': [],
@@ -147,7 +145,6 @@ class TestCreateElements(FixtureAPITestCase):
         act = Element.objects.get(id=response.json()['id'])
         self.assertEqual(act.name, 'Castle story')
         self.assertEqual(act.type, self.act_type)
-        self.assertEqual(act.source, None)
         self.assertEqual(act.worker_version, self.worker_version)
 
     def test_create_element_polygon(self):
@@ -176,7 +173,6 @@ class TestCreateElements(FixtureAPITestCase):
                 'type': page.type.slug,
                 'thumbnail_put_url': None,
                 'thumbnail_url': None,
-                'source': None,
                 'worker_version': None,
                 'classifications': [],
                 'metadata': [],
diff --git a/arkindex/documents/tests/test_create_transcriptions.py b/arkindex/documents/tests/test_create_transcriptions.py
index fcc5f14034b13e7f27a0ec01d8abe0c6101a1544..d48b2125a1d055ca2409ff89195746879529af23 100644
--- a/arkindex/documents/tests/test_create_transcriptions.py
+++ b/arkindex/documents/tests/test_create_transcriptions.py
@@ -6,10 +6,9 @@ from django.urls import reverse
 from rest_framework import status
 
 from arkindex.dataimport.models import WorkerVersion
-from arkindex.documents.models import Corpus, DataSource, Transcription
+from arkindex.documents.models import Corpus, Transcription
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.users.models import User
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestTranscriptionCreate(FixtureAPITestCase):
@@ -21,7 +20,6 @@ class TestTranscriptionCreate(FixtureAPITestCase):
     def setUpTestData(cls):
         super().setUpTestData()
         cls.page = cls.corpus.elements.get(name='Volume 1, page 1r')
-        cls.src = DataSource.objects.get(slug='test', type=MLToolType.Recognizer)
         cls.line = cls.corpus.elements.filter(type__slug='text_line').first()
         cls.private_corpus = Corpus.objects.create(name='Private')
         cls.private_page = cls.private_corpus.elements.create(type=cls.page.type)
@@ -77,7 +75,6 @@ class TestTranscriptionCreate(FixtureAPITestCase):
             'id': str(tr.id),
             'score': None,
             'text': 'A perfect day in a perfect place',
-            'source': None,
             'worker_version_id': None,
         })
 
@@ -174,7 +171,6 @@ class TestTranscriptionCreate(FixtureAPITestCase):
         self.assertDictEqual(response.json(), {
             'id': str(tr.id),
             'score': .42,
-            'source': None,
             'text': 'NEKUDOTAYIM',
             'worker_version_id': str(self.worker_version.id),
         })
diff --git a/arkindex/documents/tests/test_datasource.py b/arkindex/documents/tests/test_datasource.py
deleted file mode 100644
index 2730d7ccaac076e894e3dd093f832b5fd61cf3c9..0000000000000000000000000000000000000000
--- a/arkindex/documents/tests/test_datasource.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from django.test import TestCase
-
-from arkindex.documents.models import DataSource
-from arkindex_common.ml_tool import MLToolType
-
-
-class TestDataSource(TestCase):
-
-    def test_str(self):
-        ds = DataSource(
-            type=MLToolType.Classifier,
-            slug='something',
-            name='some classifier',
-            revision='1.2.3',
-            internal=False,
-        )
-        self.assertEqual(str(ds), 'something 1.2.3')
diff --git a/arkindex/documents/tests/test_edit_transcriptions.py b/arkindex/documents/tests/test_edit_transcriptions.py
index 1e5f1bd3f2b060f6a5d162e840db5011d08792f4..15147f17fdfcff4d621434e8603cf47f2006ecef 100644
--- a/arkindex/documents/tests/test_edit_transcriptions.py
+++ b/arkindex/documents/tests/test_edit_transcriptions.py
@@ -3,10 +3,9 @@ from uuid import uuid4
 from django.urls import reverse
 from rest_framework import status
 
-from arkindex.documents.models import Corpus, DataSource, Element, Transcription
+from arkindex.documents.models import Corpus, Element, Transcription
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.users.models import User
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestEditTranscription(FixtureAPITestCase):
@@ -35,15 +34,8 @@ class TestEditTranscription(FixtureAPITestCase):
         cls.corpus.corpus_right.create(user=cls.write_user, can_write=True)
 
     def setUp(self):
-        self.manual_source = DataSource.objects.create(type=MLToolType.Recognizer, slug='manual', internal=False)
-        self.manual_transcription = self.line.transcriptions.create(
-            text='A manual transcription',
-            source=self.manual_source,
-        )
-        self.private_transcription = self.private_page.transcriptions.create(
-            text='PEPE',
-            source=self.manual_source
-        )
+        self.manual_transcription = self.line.transcriptions.create(text='A manual transcription')
+        self.private_transcription = self.private_page.transcriptions.create(text='PEPE')
 
     def test_transcription_retrieve(self):
         """
@@ -53,18 +45,9 @@ class TestEditTranscription(FixtureAPITestCase):
         response = self.client.get(reverse('api:transcription-edit', kwargs={'pk': self.manual_transcription.id}))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         tr = Transcription.objects.get(id=response.json()['id'])
-        self.manual_source.refresh_from_db()
         self.assertDictEqual(response.json(), {
             'id': str(tr.id),
             'score': None,
-            'source': {
-                'id': str(self.manual_source.id),
-                'internal': False,
-                'name': '',
-                'revision': '',
-                'slug': 'manual',
-                'type': 'recognizer'
-            },
             'text': 'A manual transcription',
             'worker_version_id': None,
         })
@@ -146,7 +129,6 @@ class TestEditTranscription(FixtureAPITestCase):
                 'score': .42,
                 'zone': {'polygon': [[4, 2], [2, 4], [3, 3]], 'center': [42, 1337]},
                 'image': {'status': 'checked'},
-                'source': 'castle_source',
                 'element': 'water'
             }
         )
@@ -155,14 +137,6 @@ class TestEditTranscription(FixtureAPITestCase):
         self.assertDictEqual(response.json(), {
             'id': str(manual_tr_id),
             'score': None,
-            'source': {
-                'id': str(self.manual_source.id),
-                'internal': False,
-                'name': '',
-                'revision': '',
-                'slug': 'manual',
-                'type': 'recognizer'
-            },
             'text': 'a knight was living lonely',
             'worker_version_id': None,
         })
diff --git a/arkindex/documents/tests/test_entities.py b/arkindex/documents/tests/test_entities.py
index ba6efbf003e9a86aac35d59d6a2b57f4a7e7e53a..1f72233cc5c611976a9f9fcc691cbd818cef3593 100644
--- a/arkindex/documents/tests/test_entities.py
+++ b/arkindex/documents/tests/test_entities.py
@@ -1,6 +1,7 @@
 from django.core.exceptions import ValidationError
 
-from arkindex.documents.models import Corpus, DataSource, Entity, EntityLink, EntityRole, MetaData, MLToolType
+from arkindex.dataimport.models import WorkerVersion
+from arkindex.documents.models import Corpus, Entity, EntityLink, EntityRole, MetaData
 from arkindex.project.tests import FixtureTestCase
 from arkindex_common.enums import EntityType, MetaType
 
@@ -10,16 +11,21 @@ class TestSaveEntities(FixtureTestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        source = DataSource.objects.create(type=MLToolType.NER, slug='entity', internal=False)
+        worker_version = WorkerVersion.objects.first()
         cls.corpus1 = Corpus.objects.create(name='corpus 1')
         cls.corpus2 = Corpus.objects.create(name='corpus 2')
         cls.parent = Entity.objects.create(
             name='parent',
             type=EntityType.Organization,
             corpus=cls.corpus1,
-            source=source
+            worker_version=worker_version,
+        )
+        cls.child = Entity.objects.create(
+            type=EntityType.Person,
+            corpus=cls.corpus1,
+            name="child",
+            worker_version=worker_version,
         )
-        cls.child = Entity.objects.create(type=EntityType.Person, corpus=cls.corpus1, name="child", source=source)
         cls.role = EntityRole.objects.create(
             parent_name='organization',
             child_name='person',
diff --git a/arkindex/documents/tests/test_entities_api.py b/arkindex/documents/tests/test_entities_api.py
index 3910f54e7872a2a6d40f3f12a2f7dd49c2099d6d..c1e945977ccd210b34d5caa41f69c11ea4b40df0 100644
--- a/arkindex/documents/tests/test_entities_api.py
+++ b/arkindex/documents/tests/test_entities_api.py
@@ -8,17 +8,7 @@ from elasticsearch.exceptions import NotFoundError
 from rest_framework import status
 
 from arkindex.dataimport.models import WorkerVersion
-from arkindex.documents.models import (
-    Corpus,
-    DataSource,
-    Element,
-    Entity,
-    EntityLink,
-    EntityRole,
-    EntityType,
-    MLToolType,
-    TranscriptionEntity,
-)
+from arkindex.documents.models import Corpus, Element, Entity, EntityLink, EntityRole, EntityType, TranscriptionEntity
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex_common.enums import MetaType
 
@@ -28,15 +18,9 @@ class TestEntitiesAPI(FixtureAPITestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        cls.entity_source = DataSource.objects.create(
-            type=MLToolType.NER,
-            slug='entity',
-            name='Test NER',
-            internal=True,
-        )
-        cls.source = DataSource.objects.get(slug='test', type=MLToolType.Recognizer)
         cls.private_corpus = Corpus.objects.create(name='private')
-        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
+        cls.worker_version_1 = WorkerVersion.objects.get(worker__slug='reco')
+        cls.worker_version_2 = WorkerVersion.objects.get(worker__slug='dla')
         cls.page = cls.corpus.elements.get(name='Volume 1, page 1r')
         cls.element_type = cls.corpus.types.get(slug='text_line')
 
@@ -46,13 +30,13 @@ class TestEntitiesAPI(FixtureAPITestCase):
             type=EntityType.Person,
             corpus=self.corpus,
             name='entity 1',
-            source_id=self.source.id
+            worker_version=self.worker_version_1,
         )
         self.entity_bis = Entity.objects.create(
             type=EntityType.Location,
             corpus=self.corpus,
             name='entity 2',
-            source_id=self.source.id
+            worker_version=self.worker_version_2,
         )
         self.role = EntityRole.objects.create(
             parent_name="parent",
@@ -68,11 +52,11 @@ class TestEntitiesAPI(FixtureAPITestCase):
             type=self.element_type,
             name='Transcription',
             zone=zone,
-            source=self.source,
+            worker_version=self.worker_version_1,
         )
         self.transcription = self.element.transcriptions.create(
             text='Some transcribed text',
-            source=self.source,
+            worker_version=self.worker_version_1,
         )
         self.metadata = self.element.metadatas.create(
             name='test 1',
@@ -129,7 +113,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
             name='001',
             zone=zone,
         )
-        elt_tr = elt.transcriptions.create(source_id=self.source.id, text='goodbye')
+        elt_tr = elt.transcriptions.create(worker_version=self.worker_version_1, text='goodbye')
         TranscriptionEntity.objects.create(transcription=elt_tr, entity=self.entity, offset=42, length=7)
         with self.assertNumQueries(8):
             response = self.client.get(reverse('api:entity-elements', kwargs={'pk': str(self.entity.id)}))
@@ -239,8 +223,6 @@ class TestEntitiesAPI(FixtureAPITestCase):
 
     @patch('arkindex.project.triggers.tasks.reindex_start.delay')
     def test_create_entity_person(self, delay_mock):
-        self.entity_source.internal = True
-        self.entity_source.save()
         data = {
             'name': 'entity',
             'type': EntityType.Person.value,
@@ -249,7 +231,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                 'key': 'value',
                 'other key': 'other value'
             },
-            'worker_version': str(self.worker_version.id)
+            'worker_version': str(self.worker_version_1.id)
         }
         self.client.force_login(self.user)
         response = self.client.post(reverse('api:entity-create'), data=data, format='json')
@@ -257,7 +239,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
         entity = Entity.objects.get(id=response.json()['id'])
         self.assertEqual(entity.name, 'entity')
         self.assertEqual(entity.raw_dates, None)
-        self.assertEqual(entity.worker_version, self.worker_version)
+        self.assertEqual(entity.worker_version, self.worker_version_1)
         self.assertEqual(delay_mock.call_count, 1)
         self.assertEqual(delay_mock.call_args, call(
             corpus_id=None,
@@ -273,8 +255,6 @@ class TestEntitiesAPI(FixtureAPITestCase):
 
     @patch('arkindex.project.triggers.tasks.reindex_start.delay')
     def test_create_entity_number(self, delay_mock):
-        self.entity_source.internal = True
-        self.entity_source.save()
         data = {
             'name': '300g',
             'type': EntityType.Number.value,
@@ -283,7 +263,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                 'key': 'value',
                 'other key': 'other value'
             },
-            'worker_version': str(self.worker_version.id)
+            'worker_version': str(self.worker_version_1.id)
         }
         self.client.force_login(self.user)
         response = self.client.post(reverse('api:entity-create'), data=data, format='json')
@@ -291,7 +271,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
         entity = Entity.objects.get(id=response.json()['id'])
         self.assertEqual(entity.name, '300g')
         self.assertEqual(entity.raw_dates, None)
-        self.assertEqual(entity.worker_version, self.worker_version)
+        self.assertEqual(entity.worker_version, self.worker_version_1)
         self.assertEqual(delay_mock.call_count, 1)
         self.assertEqual(delay_mock.call_args, call(
             corpus_id=None,
@@ -307,8 +287,6 @@ class TestEntitiesAPI(FixtureAPITestCase):
 
     @patch('arkindex.project.triggers.tasks.reindex_start.delay')
     def test_create_entity_date(self, delay_mock):
-        self.entity_source.internal = True
-        self.entity_source.save()
         data = {
             'name': '1789',
             'type': EntityType.Date.value,
@@ -317,7 +295,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                 'key': 'value',
                 'other key': 'other value'
             },
-            'worker_version': str(self.worker_version.id)
+            'worker_version': str(self.worker_version_1.id)
         }
         self.client.force_login(self.user)
         response = self.client.post(reverse('api:entity-create'), data=data, format='json')
@@ -325,7 +303,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
         entity = Entity.objects.get(id=response.json()['id'])
         self.assertEqual(entity.name, '1789')
         self.assertEqual(entity.raw_dates, entity.name)
-        self.assertEqual(entity.worker_version, self.worker_version)
+        self.assertEqual(entity.worker_version, self.worker_version_1)
         self.assertEqual(delay_mock.call_count, 1)
         self.assertEqual(delay_mock.call_args, call(
             corpus_id=None,
@@ -348,7 +326,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                 'key': 'value',
                 'other key': 'other value'
             },
-            'ner': self.entity_source.slug
+            'worker_version': str(self.worker_version_1.id)
         }
         response = self.client.post(reverse('api:entity-create'), data=data, format='json')
         self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
@@ -363,15 +341,14 @@ class TestEntitiesAPI(FixtureAPITestCase):
                 'key': 'value',
                 'other key': 'other value'
             },
-            'worker_version': str(self.worker_version.id)
+            'worker_version': str(self.worker_version_1.id)
         }
         self.client.force_login(self.user)
         response = self.client.post(reverse('api:entity-create'), data=data, format='json')
         self.assertEqual(response.status_code, status.HTTP_201_CREATED)
         entity = Entity.objects.get(id=response.json()['id'])
         self.assertEqual(entity.name, '1789')
-        self.assertEqual(entity.source, None)
-        self.assertEqual(entity.worker_version, self.worker_version)
+        self.assertEqual(entity.worker_version, self.worker_version_1)
         self.assertEqual(delay_mock.call_count, 1)
         self.assertEqual(delay_mock.call_args, call(
             corpus_id=None,
@@ -390,7 +367,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
             type=EntityType.Location,
             corpus=self.corpus,
             name="child",
-            source_id=self.source.id
+            worker_version=self.worker_version_1,
         )
         data = {
             'parent': str(self.entity.id),
@@ -410,7 +387,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
             type=EntityType.Location,
             corpus=self.corpus,
             name="child",
-            source_id=self.source.id
+            worker_version=self.worker_version_1,
         )
         data = {
             'parent': str(self.entity.id),
@@ -425,7 +402,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
             type=EntityType.Person,
             corpus=self.corpus,
             name="child",
-            source_id=self.source.id
+            worker_version=self.worker_version_1,
         )
         data = {
             'parent': str(self.entity.id),
@@ -489,7 +466,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
             type=EntityType.Person,
             corpus=self.private_corpus,
             name="a private entity",
-            source_id=self.source.id
+            worker_version=self.worker_version_1,
         )
         self.tr_entities_sample.update({'entity': ent.id})
         response = self.client.post(
@@ -563,15 +540,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                     'metas': None,
                     'validated': self.entity_bis.validated,
                     'dates': [],
-                    'source': {
-                        'id': str(self.source.id),
-                        'type': self.source.type.value,
-                        'slug': self.source.slug,
-                        'name': self.source.name,
-                        'revision': self.source.revision,
-                        'internal': self.source.internal,
-                    },
-                    'worker_version_id': None,
+                    'worker_version_id': str(self.worker_version_2.id),
                 },
                 'length': self.transcriptionentity.length,
                 'offset': self.transcriptionentity.offset
@@ -579,10 +548,6 @@ class TestEntitiesAPI(FixtureAPITestCase):
         )
 
     def test_list_transcription_entities_worker_version(self):
-        self.entity_bis.source = None
-        self.entity_bis.worker_version = self.worker_version
-        self.entity_bis.save()
-
         response = self.client.get(reverse('api:transcription-entities', kwargs={'pk': str(self.transcription.id)}))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         self.assertListEqual(
@@ -595,8 +560,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                     'metas': None,
                     'validated': False,
                     'dates': [],
-                    'source': None,
-                    'worker_version_id': str(self.worker_version.id),
+                    'worker_version_id': str(self.worker_version_2.id),
                 },
                 'length': 8,
                 'offset': 2
@@ -627,10 +591,11 @@ class TestEntitiesAPI(FixtureAPITestCase):
         md = self.element.metadatas.create(name='some_metadata', type=MetaType.Location, value='something')
         md.entity = self.entity_bis
         md.save()
-        with self.assertNumQueries(9):
+        with self.assertNumQueries(6):
             response = self.client.get(reverse('api:element-entities', kwargs={'pk': str(self.element.id)}))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
+        self.maxDiff = None
         self.assertDictEqual(
             data,
             {
@@ -645,15 +610,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                         'metas': None,
                         'validated': t.entity.validated,
                         'dates': [],
-                        'source': {
-                            'id': str(self.source.id),
-                            'type': self.source.type.value,
-                            'slug': self.source.slug,
-                            'name': self.source.name,
-                            'revision': self.source.revision,
-                            'internal': self.source.internal,
-                        },
-                        'worker_version_id': None,
+                        'worker_version_id': str(self.worker_version_2.id),
                     },
                     'offset': t.offset,
                     'length': t.length
@@ -666,15 +623,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                         'metas': None,
                         'validated': m.entity.validated,
                         'dates': [],
-                        'source': {
-                            'id': str(self.source.id),
-                            'type': self.source.type.value,
-                            'slug': self.source.slug,
-                            'name': self.source.name,
-                            'revision': self.source.revision,
-                            'internal': self.source.internal,
-                        },
-                        'worker_version_id': None,
+                        'worker_version_id': str(m.entity.worker_version_id),
                     },
                     'id': str(m.id),
                     'type': m.type.value,
@@ -704,14 +653,10 @@ class TestEntitiesAPI(FixtureAPITestCase):
         self.assertEqual(response.json(), {'worker_version': ['This worker version does not exist.']})
 
     def test_list_element_entities_worker_version(self):
-        self.entity.source = None
-        self.entity.worker_version = self.worker_version
-        self.entity.save()
-
         with self.assertNumQueries(6):
             response = self.client.get(
                 reverse('api:element-entities', kwargs={'pk': str(self.element.id)}),
-                data={'worker_version': str(self.worker_version.id)}
+                data={'worker_version': str(self.worker_version_1.id)}
             )
             self.assertEqual(response.status_code, status.HTTP_200_OK)
 
@@ -737,8 +682,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                             'validated': False,
                             'dates': [],
                             'metas': None,
-                            'source': None,
-                            'worker_version_id': str(self.worker_version.id),
+                            'worker_version_id': str(self.worker_version_1.id),
                         },
                     }
                 ],
@@ -883,15 +827,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                     'metas': None,
                     'validated': self.entity.validated,
                     'dates': [],
-                    'source': {
-                        'id': str(self.source.id),
-                        'type': self.source.type.value,
-                        'slug': self.source.slug,
-                        'name': self.source.name,
-                        'revision': self.source.revision,
-                        'internal': self.source.internal,
-                    },
-                    'worker_version_id': None,
+                    'worker_version_id': str(self.worker_version_1.id),
                 },
                 'child': {
                     'id': str(self.entity_bis.id),
@@ -900,15 +836,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                     'metas': None,
                     'validated': self.entity_bis.validated,
                     'dates': [],
-                    'source': {
-                        'id': str(self.source.id),
-                        'type': self.source.type.value,
-                        'slug': self.source.slug,
-                        'name': self.source.name,
-                        'revision': self.source.revision,
-                        'internal': self.source.internal,
-                    },
-                    'worker_version_id': None,
+                    'worker_version_id': str(self.worker_version_2.id),
                 },
                 'role': {
                     'id': self.role.id,
@@ -934,7 +862,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
             'name': 'entity',
             'type': EntityType.Person.value,
             'corpus': str(self.corpus.id),
-            'worker_version': str(self.worker_version.id)
+            'worker_version': str(self.worker_version_1.id)
         }
         self.client.force_login(self.user)
         response = self.client.post(reverse('api:entity-create'), data=data, format='json')
diff --git a/arkindex/documents/tests/test_indexer.py b/arkindex/documents/tests/test_indexer.py
index 52a7d9a9a25be7670b7650d94ad30673814b2920..3981f62a9af86f10789f37e9df598e9313e7a5e1 100644
--- a/arkindex/documents/tests/test_indexer.py
+++ b/arkindex/documents/tests/test_indexer.py
@@ -3,8 +3,8 @@ from unittest.mock import MagicMock, call, patch
 from elasticsearch import Elasticsearch
 from elasticsearch.exceptions import NotFoundError
 
+from arkindex.dataimport.models import WorkerVersion
 from arkindex.documents.indexer import Indexer
-from arkindex.documents.models import DataSource, MLToolType
 from arkindex.project.tests import FixtureTestCase
 from arkindex_common.enums import EntityType
 
@@ -14,9 +14,13 @@ class TestIndexer(FixtureTestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        source = DataSource.objects.create(type=MLToolType.NER, slug='entity', internal=True)
+        worker_version = WorkerVersion.objects.first()
         for i in range(10):
-            cls.corpus.entities.create(name='ES Dummy {}'.format(i), type=EntityType.Misc, source=source)
+            cls.corpus.entities.create(
+                name=f'ES Dummy {i}',
+                type=EntityType.Misc,
+                worker_version=worker_version,
+            )
 
     @patch('arkindex.documents.indexer.Elasticsearch')
     def test_drop_index(self, es_mock):
diff --git a/arkindex/documents/tests/test_manifest.py b/arkindex/documents/tests/test_manifest.py
index 659e5d351767a4fa2ad29ada75a8baa61a7316a6..4eaafa569977824d86e33eac4e62473d26dc0dcf 100644
--- a/arkindex/documents/tests/test_manifest.py
+++ b/arkindex/documents/tests/test_manifest.py
@@ -4,10 +4,10 @@ from django.urls import reverse
 from rest_framework import status
 from tripoli import IIIFValidator
 
-from arkindex.documents.models import DataSource, Element
+from arkindex.dataimport.models import WorkerVersion
+from arkindex.documents.models import Element
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex_common.enums import MetaType
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestFolderManifestSerializer(FixtureAPITestCase):
@@ -135,11 +135,11 @@ class TestFolderManifestSerializer(FixtureAPITestCase):
 
     def test_with_classification(self):
         self.assertFalse(self.page.classifications.exists())
-        source = DataSource.objects.get(slug='test', type=MLToolType.Recognizer)
+        worker_version = WorkerVersion.objects.first()
         text_class = self.corpus.ml_classes.create(name='text')
         cover_class = self.corpus.ml_classes.create(name='cover')
-        self.page.classifications.create(ml_class=text_class, confidence=0.42, source=source)
-        self.page.classifications.create(ml_class=cover_class, confidence=0.12, source=source)
+        self.page.classifications.create(ml_class=text_class, confidence=0.42, worker_version=worker_version)
+        self.page.classifications.create(ml_class=cover_class, confidence=0.12, worker_version=worker_version)
 
         response = self.client.get(reverse('api:folder-manifest', kwargs={'pk': self.vol.id}))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
diff --git a/arkindex/documents/tests/test_metadata.py b/arkindex/documents/tests/test_metadata.py
index 989e83bcf0b5b261b1cebb32fdcfccb88a2788c1..1802992d19a86bd810c810957c45ae07b5a6666e 100644
--- a/arkindex/documents/tests/test_metadata.py
+++ b/arkindex/documents/tests/test_metadata.py
@@ -4,11 +4,11 @@ from django.test import override_settings
 from django.urls import reverse
 from rest_framework import status
 
-from arkindex.documents.models import AllowedMetaData, Corpus, DataSource, MetaData
+from arkindex.dataimport.models import WorkerVersion
+from arkindex.documents.models import AllowedMetaData, Corpus, MetaData
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.users.models import User
 from arkindex_common.enums import EntityType, MetaType
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestMetaData(FixtureAPITestCase):
@@ -31,7 +31,7 @@ class TestMetaData(FixtureAPITestCase):
                 (MetaType.Reference, '_id'),
             )
         )
-        cls.source = DataSource.objects.get(slug='test', type=MLToolType.Recognizer)
+        cls.worker_version = WorkerVersion.objects.first()
 
     def setUp(self):
         super().setUp()
@@ -480,7 +480,11 @@ class TestMetaData(FixtureAPITestCase):
 
     def test_create_metadata_entity(self):
         self.client.force_login(self.superuser)
-        entity = self.corpus.entities.create(name='Texas', type=EntityType.Location, source=self.source)
+        entity = self.corpus.entities.create(
+            name='Texas',
+            type=EntityType.Location,
+            worker_version=self.worker_version,
+        )
         response = self.client.post(
             reverse('api:element-metadata', kwargs={'pk': str(self.vol.id)}),
             data={'type': 'location', 'name': 'location', 'value': 'Texas', 'entity': entity.id}
@@ -490,7 +494,11 @@ class TestMetaData(FixtureAPITestCase):
 
     def test_patch_metadata_entity(self):
         self.client.force_login(self.superuser)
-        entity = self.corpus.entities.create(name='Texas', type=EntityType.Location, source=self.source)
+        entity = self.corpus.entities.create(
+            name='Texas',
+            type=EntityType.Location,
+            worker_version=self.worker_version,
+        )
         metadata = self.vol.metadatas.create(type=MetaType.Location, name='location', value='Texas')
         response = self.client.patch(
             reverse('api:metadata-edit', kwargs={'pk': str(metadata.id)}),
@@ -502,7 +510,11 @@ class TestMetaData(FixtureAPITestCase):
 
     def test_patch_metadata_entity_none(self):
         self.client.force_login(self.superuser)
-        entity = self.corpus.entities.create(name='Texas', type=EntityType.Location, source=self.source)
+        entity = self.corpus.entities.create(
+            name='Texas',
+            type=EntityType.Location,
+            worker_version=self.worker_version,
+        )
         metadata = self.vol.metadatas.create(type=MetaType.Location, name='location', value='Texas', entity=entity)
         response = self.client.patch(
             reverse('api:metadata-edit', kwargs={'pk': str(metadata.id)}),
@@ -515,7 +527,11 @@ class TestMetaData(FixtureAPITestCase):
 
     def test_create_metadata_entity_corpus_check(self):
         self.client.force_login(self.superuser)
-        entity = self.private_corpus.entities.create(name='Texas', type=EntityType.Location, source=self.source)
+        entity = self.private_corpus.entities.create(
+            name='Texas',
+            type=EntityType.Location,
+            worker_version=self.worker_version,
+        )
         response = self.client.post(
             reverse('api:element-metadata', kwargs={'pk': str(self.vol.id)}),
             data={'type': 'location', 'name': 'location', 'value': 'Texas', 'entity': entity.id}
@@ -524,7 +540,11 @@ class TestMetaData(FixtureAPITestCase):
 
     def test_patch_metadata_entity_corpus_check(self):
         self.client.force_login(self.superuser)
-        entity = self.private_corpus.entities.create(name='Texas', type=EntityType.Location, source=self.source)
+        entity = self.private_corpus.entities.create(
+            name='Texas',
+            type=EntityType.Location,
+            worker_version=self.worker_version,
+        )
         metadata = self.vol.metadatas.create(type=MetaType.Location, name='location', value='Texas')
         response = self.client.patch(
             reverse('api:metadata-edit', kwargs={'pk': str(metadata.id)}),
diff --git a/arkindex/documents/tests/test_ml_results.py b/arkindex/documents/tests/test_ml_results.py
deleted file mode 100644
index 83e932fc023423b5f417bf4d6088bddd062408e3..0000000000000000000000000000000000000000
--- a/arkindex/documents/tests/test_ml_results.py
+++ /dev/null
@@ -1,225 +0,0 @@
-from unittest.mock import call, patch
-
-from django.test import override_settings
-from django.urls import reverse
-from rest_framework import status
-
-from arkindex.documents.models import DataSource, Entity, Transcription
-from arkindex.project.tests import FixtureTestCase
-from arkindex_common.enums import EntityType, MetaType
-
-
-class TestMLResults(FixtureTestCase):
-    """
-    Tests for ML results-related APIs
-    """
-
-    @classmethod
-    def setUpTestData(cls):
-        super().setUpTestData()
-        cls.recognizer = DataSource.objects.get(name='Test Recognizer')
-        cls.folder = cls.corpus.elements.get(name='Volume 1', type__folder=True)
-        cls.page = cls.corpus.elements.get(name='Volume 1, page 1r')
-
-        entity = cls.corpus.entities.create(
-            name='An entity',
-            type=EntityType.Misc,
-            source=cls.recognizer,
-        )
-        entity2 = cls.corpus.entities.create(
-            name='Another entity',
-            type=EntityType.Misc,
-            source=cls.recognizer,
-        )
-
-        ml_class = cls.corpus.ml_classes.create(name='Some class')
-        cls.folder.classifications.create(ml_class=ml_class, source=cls.recognizer, confidence=0.42)
-        cls.page.classifications.create(ml_class=ml_class, source=cls.recognizer, confidence=0.85)
-        cls.page.metadatas.create(name='key', value='value', type=MetaType.Text, entity=entity)
-        cls.page.transcriptions.first().transcription_entities.create(
-            entity=entity2, offset=0, length=1,
-        )
-
-    def test_element_stats_requires_login(self):
-        response = self.client.get(reverse('api:element-ml-stats', kwargs={'pk': str(self.page.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    def test_element_stats_requires_admin(self):
-        self.client.force_login(self.user)
-        response = self.client.get(reverse('api:element-ml-stats', kwargs={'pk': str(self.page.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    def test_element_stats(self):
-        self.client.force_login(self.superuser)
-        self.assertEqual(self.page.transcriptions.count(), 1)
-        self.assertEqual(self.page.classifications.count(), 1)
-        self.assertEqual(Entity.objects.filter(transcriptions__element=self.page).count(), 1)
-        self.assertEqual(Entity.objects.filter(metadatas__element=self.page).count(), 1)
-
-        with self.assertNumQueries(7):
-            response = self.client.get(reverse('api:element-ml-stats', kwargs={'pk': str(self.page.id)}))
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.assertListEqual(response.json(), [
-            {
-                'id': str(self.recognizer.id),
-                'type': 'recognizer',
-                'slug': 'test',
-                'name': 'Test Recognizer',
-                'revision': '4.2',
-                'internal': False,
-                'classifications_count': 1,
-                'transcriptions_count': 1,
-                'entities_count': 2,
-            }
-        ])
-
-    def test_element_stats_folder(self):
-        self.client.force_login(self.superuser)
-        with self.assertNumQueries(7):
-            response = self.client.get(reverse('api:element-ml-stats', kwargs={'pk': str(self.folder.id)}))
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.assertListEqual(response.json(), [
-            {
-                'id': str(self.recognizer.id),
-                'type': 'recognizer',
-                'slug': 'test',
-                'name': 'Test Recognizer',
-                'revision': '4.2',
-                'internal': False,
-                'classifications_count': 2,
-                'transcriptions_count': 10,
-                'entities_count': 2,
-            }
-        ])
-
-    def test_corpus_stats_requires_login(self):
-        response = self.client.get(reverse('api:corpus-ml-stats', kwargs={'pk': str(self.corpus.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    def test_corpus_stats_requires_admin(self):
-        self.client.force_login(self.user)
-        response = self.client.get(reverse('api:corpus-ml-stats', kwargs={'pk': str(self.corpus.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    def test_corpus_stats(self):
-        self.client.force_login(self.superuser)
-        self.assertEqual(self.folder.classifications.count(), 1)
-        self.assertEqual(self.page.classifications.count(), 1)
-        self.assertEqual(Entity.objects.filter(transcriptions__element=self.page).count(), 1)
-        self.assertEqual(Entity.objects.filter(metadatas__element=self.page).count(), 1)
-        self.assertEqual(Transcription.objects.filter(element__corpus=self.corpus).count(), 10)
-
-        with self.assertNumQueries(7):
-            response = self.client.get(reverse('api:corpus-ml-stats', kwargs={'pk': str(self.corpus.id)}))
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.assertListEqual(response.json(), [
-            {
-                'id': str(self.recognizer.id),
-                'type': 'recognizer',
-                'slug': 'test',
-                'name': 'Test Recognizer',
-                'revision': '4.2',
-                'internal': False,
-                'classifications_count': 2,
-                'transcriptions_count': 10,
-                'entities_count': 2,
-            }
-        ])
-
-    def test_corpus_destroy_results_requires_login(self):
-        response = self.client.delete(reverse('api:corpus-ml-stats', kwargs={'pk': str(self.corpus.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    def test_corpus_destroy_results_requires_admin(self):
-        self.client.force_login(self.user)
-        response = self.client.delete(reverse('api:corpus-ml-stats', kwargs={'pk': str(self.corpus.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    @patch('arkindex.project.triggers.tasks.ml_results_delete.delay')
-    @patch('arkindex.project.triggers.tasks.reindex_start.delay')
-    def test_corpus_destroy_results(self, reindex_delay_mock, delete_delay_mock):
-        self.client.force_login(self.superuser)
-        delete_delay_mock.return_value = 'a'
-        response = self.client.delete(reverse('api:corpus-ml-stats', kwargs={'pk': str(self.corpus.id)}))
-        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
-        self.assertEqual(delete_delay_mock.call_count, 1)
-        self.assertEqual(delete_delay_mock.call_args, call(
-            corpus_id=str(self.corpus.id),
-            element_id=None,
-            batch_size=1000,
-            user_id=self.superuser.id,
-            description=f'ML results deletion on corpus {self.corpus.id}',
-        ))
-        self.assertEqual(reindex_delay_mock.call_count, 1)
-        self.assertEqual(reindex_delay_mock.call_args, call(
-            corpus_id=str(self.corpus.id),
-            element_id=None,
-            depends_on='a',
-        ))
-
-    @override_settings(ARKINDEX_FEATURES={'search': False})
-    @patch('arkindex.project.triggers.tasks.ml_results_delete.delay')
-    @patch('arkindex.project.triggers.tasks.reindex_start.delay')
-    def test_corpus_destroy_results_no_search(self, reindex_delay_mock, delete_delay_mock):
-        self.client.force_login(self.superuser)
-        delete_delay_mock.return_value = 'a'
-        response = self.client.delete(reverse('api:corpus-ml-stats', kwargs={'pk': str(self.corpus.id)}))
-        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
-        self.assertEqual(delete_delay_mock.call_count, 1)
-        self.assertEqual(delete_delay_mock.call_args, call(
-            corpus_id=str(self.corpus.id),
-            element_id=None,
-            batch_size=1000,
-            user_id=self.superuser.id,
-            description=f'ML results deletion on corpus {self.corpus.id}',
-        ))
-        self.assertFalse(reindex_delay_mock.called)
-
-    def test_element_destroy_results_requires_login(self):
-        response = self.client.delete(reverse('api:element-ml-stats', kwargs={'pk': str(self.page.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    def test_element_destroy_results_requires_admin(self):
-        self.client.force_login(self.user)
-        response = self.client.delete(reverse('api:element-ml-stats', kwargs={'pk': str(self.page.id)}))
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-
-    @patch('arkindex.project.triggers.tasks.ml_results_delete.delay')
-    @patch('arkindex.project.triggers.tasks.reindex_start.delay')
-    def test_element_destroy_results(self, reindex_delay_mock, delete_delay_mock):
-        self.client.force_login(self.superuser)
-        delete_delay_mock.return_value = 'a'
-        response = self.client.delete(reverse('api:element-ml-stats', kwargs={'pk': str(self.page.id)}))
-        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
-        self.assertEqual(delete_delay_mock.call_count, 1)
-        self.assertEqual(delete_delay_mock.call_args, call(
-            corpus_id=None,
-            element_id=str(self.page.id),
-            batch_size=1000,
-            user_id=self.superuser.id,
-            description=f'ML results deletion on element {self.page.id}',
-        ))
-        self.assertEqual(reindex_delay_mock.call_count, 1)
-        self.assertEqual(reindex_delay_mock.call_args, call(
-            corpus_id=None,
-            element_id=str(self.page.id),
-            depends_on='a',
-        ))
-
-    @override_settings(ARKINDEX_FEATURES={'search': False})
-    @patch('arkindex.project.triggers.tasks.ml_results_delete.delay')
-    @patch('arkindex.project.triggers.tasks.reindex_start.delay')
-    def test_element_destroy_results_no_search(self, reindex_delay_mock, delete_delay_mock):
-        self.client.force_login(self.superuser)
-        delete_delay_mock.return_value = 'a'
-        response = self.client.delete(reverse('api:element-ml-stats', kwargs={'pk': str(self.page.id)}))
-        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
-        self.assertEqual(delete_delay_mock.call_count, 1)
-        self.assertEqual(delete_delay_mock.call_args, call(
-            corpus_id=None,
-            element_id=str(self.page.id),
-            batch_size=1000,
-            user_id=self.superuser.id,
-            description=f'ML results deletion on element {self.page.id}',
-        ))
-        self.assertFalse(reindex_delay_mock.called)
diff --git a/arkindex/documents/tests/test_moderation.py b/arkindex/documents/tests/test_moderation.py
index c8819aeaf4aee7965ffb969134d4e9c8e6b75976..bc0a9b222e56859af91b881df7ebbbbf4c277ec8 100644
--- a/arkindex/documents/tests/test_moderation.py
+++ b/arkindex/documents/tests/test_moderation.py
@@ -3,15 +3,7 @@ from django.urls import reverse
 from rest_framework import status
 
 from arkindex.dataimport.models import WorkerVersion
-from arkindex.documents.models import (
-    Classification,
-    ClassificationState,
-    Corpus,
-    DataSource,
-    Element,
-    MLClass,
-    MLToolType,
-)
+from arkindex.documents.models import Classification, ClassificationState, Corpus, Element, MLClass
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.users.models import User
 
@@ -26,31 +18,9 @@ class TestClasses(FixtureAPITestCase):
         cls.act_type = cls.corpus.types.get(slug='act')
         cls.element = Element.objects.get(name='Volume 1, page 1v')
         cls.folder = cls.corpus.elements.get(name='Volume 1')
-        cls.worker_version = WorkerVersion.objects.get(worker__slug='dla')
+        cls.worker_version_1 = WorkerVersion.objects.get(worker__slug='dla')
+        cls.worker_version_2 = WorkerVersion.objects.get(worker__slug='reco')
         cls.internal_user = User.objects.get_by_natural_key('internal@internal.fr')
-        cls.classifier_source = DataSource.objects.create(
-            type=MLToolType.Classifier,
-            slug='some_classifier',
-            revision='1.3.3.7',
-            internal=False,
-        )
-
-    def _create_classification_from_source(self):
-        return self.element.classifications.create(
-            source=self.classifier_source,
-            ml_class=self.text,
-            confidence=.5,
-        )
-
-    def _serialized_source(self, classification):
-        return {
-            'id': str(classification.source.id),
-            'type': classification.source.type.value,
-            'slug': classification.source.slug,
-            'name': classification.source.name,
-            'revision': classification.source.revision,
-            'internal': classification.source.internal
-        }
 
     def test_manual_classification_creation(self):
         """
@@ -192,7 +162,7 @@ class TestClasses(FixtureAPITestCase):
             response = self.client.post(reverse('api:classification-create'), {
                 'element': str(self.element.id),
                 'ml_class': str(self.text.id),
-                'worker_version': str(self.worker_version.id)
+                'worker_version': str(self.worker_version_1.id)
             })
             self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
 
@@ -210,12 +180,12 @@ class TestClasses(FixtureAPITestCase):
                 'ml_class': str(self.text.id),
                 'confidence': 0.42,
                 'high_confidence': False,
-                'worker_version': str(self.worker_version.id)
+                'worker_version': str(self.worker_version_1.id)
             })
             self.assertEqual(response.status_code, status.HTTP_201_CREATED)
 
         classification = self.element.classifications.get()
-        self.assertEqual(classification.worker_version, self.worker_version)
+        self.assertEqual(classification.worker_version, self.worker_version_1)
         self.assertEqual(classification.ml_class, self.text)
         self.assertEqual(classification.state, ClassificationState.Pending)
         self.assertEqual(classification.confidence, 0.42)
@@ -227,15 +197,14 @@ class TestClasses(FixtureAPITestCase):
             response = self.client.post(reverse('api:classification-create'), {
                 'element': str(self.element.id),
                 'ml_class': str(self.text.id),
-                'worker_version': str(self.worker_version.id),
+                'worker_version': str(self.worker_version_1.id),
                 'confidence': 0.42,
                 'high_confidence': False,
             })
             self.assertEqual(response.status_code, status.HTTP_201_CREATED)
 
         classification = self.element.classifications.get()
-        self.assertEqual(classification.source, None)
-        self.assertEqual(classification.worker_version, self.worker_version)
+        self.assertEqual(classification.worker_version, self.worker_version_1)
         self.assertEqual(classification.ml_class, self.text)
         self.assertEqual(classification.state, ClassificationState.Pending)
         self.assertEqual(classification.confidence, 0.42)
@@ -250,14 +219,14 @@ class TestClasses(FixtureAPITestCase):
             response = self.client.post(reverse('api:classification-create'), {
                 'element': str(self.element.id),
                 'ml_class': str(self.text.id),
-                'worker_version': str(self.worker_version.id),
+                'worker_version': str(self.worker_version_1.id),
                 'confidence': 0,
                 'high_confidence': False,
             })
             self.assertEqual(response.status_code, status.HTTP_201_CREATED)
 
         classification = self.element.classifications.get()
-        self.assertEqual(classification.worker_version, self.worker_version)
+        self.assertEqual(classification.worker_version, self.worker_version_1)
         self.assertEqual(classification.ml_class, self.text)
         self.assertEqual(classification.state, ClassificationState.Pending)
         self.assertEqual(classification.confidence, 0)
@@ -265,7 +234,7 @@ class TestClasses(FixtureAPITestCase):
 
     def test_classification_validate(self):
         classification = self.element.classifications.create(
-            worker_version=self.worker_version,
+            worker_version=self.worker_version_1,
             ml_class=self.text,
             confidence=.1
         )
@@ -277,8 +246,7 @@ class TestClasses(FixtureAPITestCase):
 
         self.assertDictEqual(response.json(), {
             'id': str(classification.id),
-            'source': None,
-            'worker_version': str(self.worker_version.id),
+            'worker_version': str(self.worker_version_1.id),
             'ml_class': {
                 'id': str(classification.ml_class.id),
                 'name': classification.ml_class.name
@@ -293,52 +261,29 @@ class TestClasses(FixtureAPITestCase):
         self.assertEqual(classification.moderator, self.user)
 
     def test_classification_validate_without_permissions(self):
-        classification = self._create_classification_from_source()
+        classification = self.element.classifications.create(
+            ml_class=self.text,
+            confidence=.5,
+        )
         with self.assertNumQueries(0):
             response = self.client.put(reverse('api:classification-validate', kwargs={'pk': classification.id}))
             self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
 
-    def test_source_classification_reject(self):
-        self.client.force_login(self.user)
-        classification = self._create_classification_from_source()
-
-        with self.assertNumQueries(6):
-            response = self.client.put(reverse('api:classification-reject', kwargs={'pk': classification.id}))
-            self.assertEqual(response.status_code, status.HTTP_200_OK)
-
-        self.assertDictEqual(response.json(), {
-            'id': str(classification.id),
-            'source': self._serialized_source(classification),
-            'worker_version': None,
-            'ml_class': {
-                'id': str(classification.ml_class.id),
-                'name': classification.ml_class.name
-            },
-            'state': ClassificationState.Rejected.value,
-            'confidence': classification.confidence,
-            'high_confidence': False
-        })
-
-        # Ensure moderator has been set
-        classification.refresh_from_db()
-        self.assertEqual(classification.moderator, self.user)
-
     def test_worker_classification_reject(self):
         self.client.force_login(self.user)
         classification = self.element.classifications.create(
-            worker_version=self.worker_version,
+            worker_version=self.worker_version_1,
             ml_class=self.text,
             confidence=.1,
         )
 
-        with self.assertNumQueries(6):
+        with self.assertNumQueries(5):
             response = self.client.put(reverse('api:classification-reject', kwargs={'pk': classification.id}))
             self.assertEqual(response.status_code, status.HTTP_200_OK)
 
         self.assertDictEqual(response.json(), {
             'id': str(classification.id),
-            'source': None,
-            'worker_version': str(self.worker_version.id),
+            'worker_version': str(self.worker_version_1.id),
             'ml_class': {
                 'id': str(classification.ml_class.id),
                 'name': classification.ml_class.name
@@ -352,24 +297,6 @@ class TestClasses(FixtureAPITestCase):
         classification.refresh_from_db()
         self.assertEqual(classification.moderator, self.user)
 
-    def test_classification_reject_manual_source_delete(self):
-        """
-        A rejected classifications from a manual source should be automatically deleted
-        """
-        self.client.force_login(self.user)
-        classification = self.element.classifications.create(
-            source=DataSource.objects.create(slug='manual', type=MLToolType.Classifier, internal=False),
-            ml_class=self.text,
-            confidence=.42,
-        )
-
-        with self.assertNumQueries(5):
-            response = self.client.put(reverse('api:classification-reject', kwargs={'pk': classification.id}))
-            self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
-
-        with self.assertRaises(Classification.DoesNotExist):
-            classification.refresh_from_db()
-
     def test_manual_classification_reject_delete(self):
         """
         A classifications with no worker version should be deleted when rejected
@@ -385,26 +312,28 @@ class TestClasses(FixtureAPITestCase):
             classification.refresh_from_db()
 
     def test_classification_reject_without_permissions(self):
-        classification = self._create_classification_from_source()
+        classification = self.element.classifications.create(ml_class=self.text, confidence=.42)
         with self.assertNumQueries(0):
             response = self.client.put(reverse('api:classification-reject', kwargs={'pk': classification.id}))
             self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
 
     def test_classification_can_still_be_moderated(self):
         self.client.force_login(self.user)
-        classification = self._create_classification_from_source()
-        classification.moderator = self.user
-        classification.state = ClassificationState.Validated.value
-        classification.save()
+        classification = self.element.classifications.create(
+            ml_class=self.text,
+            confidence=.5,
+            moderator=self.user,
+            state=ClassificationState.Validated,
+            worker_version=self.worker_version_2,
+        )
 
         # First try to reject
-        with self.assertNumQueries(6):
+        with self.assertNumQueries(5):
             response = self.client.put(reverse('api:classification-reject', kwargs={'pk': classification.id}))
             self.assertEqual(response.status_code, status.HTTP_200_OK)
 
         self.assertDictEqual(response.json(), {
             'id': str(classification.id),
-            'source': self._serialized_source(classification),
             'ml_class': {
                 'id': str(classification.ml_class.id),
                 'name': classification.ml_class.name
@@ -412,17 +341,16 @@ class TestClasses(FixtureAPITestCase):
             'state': ClassificationState.Rejected.value,
             'confidence': classification.confidence,
             'high_confidence': False,
-            'worker_version': None
+            'worker_version': str(self.worker_version_2.id),
         })
 
         # Then try to validate
-        with self.assertNumQueries(6):
+        with self.assertNumQueries(5):
             response = self.client.put(reverse('api:classification-validate', kwargs={'pk': classification.id}))
             self.assertEqual(response.status_code, status.HTTP_200_OK)
 
         self.assertDictEqual(response.json(), {
             'id': str(classification.id),
-            'source': self._serialized_source(classification),
             'ml_class': {
                 'id': str(classification.ml_class.id),
                 'name': classification.ml_class.name
@@ -430,7 +358,7 @@ class TestClasses(FixtureAPITestCase):
             'state': ClassificationState.Validated.value,
             'confidence': classification.confidence,
             'high_confidence': False,
-            'worker_version': None
+            'worker_version': str(self.worker_version_2.id)
         })
 
     def test_classification_selection_requires_login(self):
@@ -535,7 +463,7 @@ class TestClasses(FixtureAPITestCase):
             [str(self.element.id), str(self.folder.id), str(act_x.id), str(act_y.id)],
         )
 
-        with self.assertNumQueries(14):
+        with self.assertNumQueries(10):
             response = self.client.post(
                 reverse('api:classification-selection'),
                 data={'corpus_id': self.corpus.id, 'ml_class': self.text.id, 'mode': 'create'}
@@ -546,26 +474,17 @@ class TestClasses(FixtureAPITestCase):
         classification = self.folder.classifications.get()
         self.assertEqual(classification.ml_class, self.text)
         self.assertEqual(classification.state, ClassificationState.Validated)
-        self.assertEqual(classification.source.slug, 'manual')
+        self.assertIsNone(classification.worker_version)
         self.assertEqual(classification.confidence, 1)
 
         self.assertTrue(self.element.classifications.exists())
         classification = self.element.classifications.get()
         self.assertEqual(classification.ml_class, self.text)
         self.assertEqual(classification.state, ClassificationState.Validated)
-        self.assertEqual(classification.source.slug, 'manual')
+        self.assertIsNone(classification.worker_version)
         self.assertEqual(classification.confidence, 1)
 
     def test_classifications_selection_validate(self):
-        source_1 = DataSource.objects.get(slug='some_classifier')
-        source_2 = DataSource.objects.create(
-            type=MLToolType.NER,
-            slug='test',
-            name='Test NER',
-            revision='4.2',
-            internal=False,
-        )
-
         line = MLClass.objects.create(name='line', corpus=self.private_corpus)
         act_x = Element.objects.create(
             type=self.act_type,
@@ -574,7 +493,7 @@ class TestClasses(FixtureAPITestCase):
         )
         Classification.objects.create(
             element=act_x,
-            source=source_1,
+            worker_version=self.worker_version_1,
             state=ClassificationState.Pending,
             high_confidence=True,
             ml_class=line
@@ -583,14 +502,14 @@ class TestClasses(FixtureAPITestCase):
         for e in [self.folder, self.element]:
             Classification.objects.create(
                 element=e,
-                source=source_1,
+                worker_version=self.worker_version_1,
                 state=ClassificationState.Pending,
                 high_confidence=True,
                 ml_class=self.text
             )
             Classification.objects.create(
                 element=e,
-                source=source_2,
+                worker_version=self.worker_version_2,
                 state=ClassificationState.Pending,
                 high_confidence=False,
                 ml_class=self.text
@@ -613,11 +532,11 @@ class TestClasses(FixtureAPITestCase):
         for e in [self.folder, self.element]:
             classification = e.classifications.get(state=ClassificationState.Validated)
             self.assertTrue(classification.high_confidence)
-            self.assertEqual(classification.source, source_1)
+            self.assertEqual(classification.worker_version, self.worker_version_1)
 
             classification = e.classifications.get(state=ClassificationState.Pending)
             self.assertFalse(classification.high_confidence)
-            self.assertEqual(classification.source, source_2)
+            self.assertEqual(classification.worker_version, self.worker_version_2)
 
         classification = act_x.classifications.get()
         self.assertEqual(classification.state, ClassificationState.Pending)
diff --git a/arkindex/documents/tests/test_parents_elements.py b/arkindex/documents/tests/test_parents_elements.py
index e0a5a797c61587111c3eeea3474a4c4604f17c97..3d79100b54739bd0c568a2f74af8725ffedfc1b1 100644
--- a/arkindex/documents/tests/test_parents_elements.py
+++ b/arkindex/documents/tests/test_parents_elements.py
@@ -4,9 +4,8 @@ from django.urls import reverse
 from rest_framework import status
 
 from arkindex.dataimport.models import WorkerVersion
-from arkindex.documents.models import Corpus, DataSource, Element
+from arkindex.documents.models import Corpus, Element
 from arkindex.project.tests import FixtureAPITestCase
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestParentsElements(FixtureAPITestCase):
@@ -17,7 +16,6 @@ class TestParentsElements(FixtureAPITestCase):
         cls.vol = cls.corpus.elements.get(name='Volume 1')
         cls.private_corpus = Corpus.objects.create(name='private', public=False)
         cls.private_elt = cls.private_corpus.elements.create(type=cls.private_corpus.types.create(slug='type'))
-        cls.manual_source = DataSource.objects.create(type=MLToolType.Recognizer, slug='manual', internal=True)
         cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
 
     def setUp(self):
diff --git a/arkindex/documents/tests/test_patch_elements.py b/arkindex/documents/tests/test_patch_elements.py
index 993f0ad5e09d1e6fac42577aa7f15127eaaeab61..e622da2a3be99e9c072f22228a448b8ddd24474b 100644
--- a/arkindex/documents/tests/test_patch_elements.py
+++ b/arkindex/documents/tests/test_patch_elements.py
@@ -1,12 +1,11 @@
 from django.urls import reverse
 from rest_framework import status
 
-from arkindex.documents.models import Corpus, DataSource, Element
+from arkindex.documents.models import Corpus, Element
 from arkindex.images.models import ImageServer
 from arkindex.project.aws import S3FileStatus
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.users.models import User
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestPatchElements(FixtureAPITestCase):
@@ -28,7 +27,6 @@ class TestPatchElements(FixtureAPITestCase):
         )
         cls.private_corpus = Corpus.objects.create(name='private', public=False)
         cls.private_elt = cls.private_corpus.elements.create(type=cls.private_corpus.types.create(slug='type'))
-        cls.manual_source = DataSource.objects.create(type=MLToolType.Recognizer, slug='manual', internal=True)
 
     def test_patch_element_unverified(self):
         """
diff --git a/arkindex/documents/tests/test_retrieve_elements.py b/arkindex/documents/tests/test_retrieve_elements.py
index b9e593af2fcd171f7fe22ca53421569495d1dcfc..cd5566b3c274c9d966939af6888c1a8e11d56e80 100644
--- a/arkindex/documents/tests/test_retrieve_elements.py
+++ b/arkindex/documents/tests/test_retrieve_elements.py
@@ -1,10 +1,10 @@
 from django.urls import reverse
 from rest_framework import status
 
-from arkindex.documents.models import Classification, Corpus, DataSource, Entity, MLClass
+from arkindex.dataimport.models import WorkerVersion
+from arkindex.documents.models import Corpus, Entity, MLClass
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex_common.enums import EntityType, MetaType
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestRetrieveElements(FixtureAPITestCase):
@@ -14,6 +14,7 @@ class TestRetrieveElements(FixtureAPITestCase):
         super().setUpTestData()
         cls.vol = cls.corpus.elements.get(name='Volume 1')
         cls.private_corpus = Corpus.objects.create(name='private', public=False)
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
 
     def setUp(self):
         self.page = self.corpus.elements.get(name='Volume 1, page 1r')
@@ -25,9 +26,8 @@ class TestRetrieveElements(FixtureAPITestCase):
         )
 
     def test_get_element(self):
-        data_source = DataSource.objects.get(slug='test', type=MLToolType.Recognizer)
         ml_class = MLClass.objects.create(name='text', corpus=self.corpus)
-        classification = Classification.objects.create(element=self.vol, source=data_source, ml_class=ml_class)
+        classification = self.vol.classifications.create(worker_version=self.worker_version, ml_class=ml_class)
 
         response = self.client.get(reverse('api:element-retrieve', kwargs={'pk': str(self.vol.id)}))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -42,7 +42,6 @@ class TestRetrieveElements(FixtureAPITestCase):
             },
             'thumbnail_url': self.vol.thumbnail.s3_url,
             'thumbnail_put_url': None,
-            'source': None,
             'worker_version': None,
             'zone': None,
             'metadata': [],
@@ -52,15 +51,7 @@ class TestRetrieveElements(FixtureAPITestCase):
                     'confidence': None,
                     'high_confidence': False,
                     'state': 'pending',
-                    'worker_version': None,
-                    'source': {
-                        'id': str(data_source.id),
-                        'slug': 'test',
-                        'type': 'recognizer',
-                        'name': 'Test Recognizer',
-                        'revision': '4.2',
-                        'internal': False,
-                    },
+                    'worker_version': str(self.worker_version.id),
                     'ml_class': {
                         'id': str(ml_class.id),
                         'name': 'text',
@@ -157,7 +148,7 @@ class TestRetrieveElements(FixtureAPITestCase):
             type=EntityType.Person,
             corpus=self.corpus,
             name='Marc',
-            source_id=DataSource.objects.get(slug='test', type=MLToolType.Recognizer).id
+            worker_version=self.worker_version,
         )
         self.metadata.entity = entity
         self.metadata.save()
diff --git a/arkindex/documents/tests/test_search.py b/arkindex/documents/tests/test_search.py
index dd001a2ef4398a43b9755dd4555a0dffe1c2b52a..46d0702c9ab2045184abab58292303549118d57b 100644
--- a/arkindex/documents/tests/test_search.py
+++ b/arkindex/documents/tests/test_search.py
@@ -6,7 +6,8 @@ from django.urls import reverse
 from elasticsearch_dsl.connections import connections
 from rest_framework import status
 
-from arkindex.documents.models import Corpus, DataSource, Element, MLToolType, Transcription
+from arkindex.dataimport.models import WorkerVersion
+from arkindex.documents.models import Corpus, Element, Transcription
 from arkindex.project.elastic import ESTranscription
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex_common.enums import EntityType, MetaType
@@ -237,9 +238,9 @@ class TestSearchAPI(FixtureAPITestCase):
         self.assertListEqual(conditions, [{'match': {'text': 'paris'}}])
 
     def test_entity_search(self):
-        source = DataSource.objects.create(type=MLToolType.NER, slug='entity source', internal=True)
-        entity_1 = self.corpus.entities.create(type=EntityType.Person, name="an entity", source=source)
-        entity_2 = self.corpus.entities.create(type=EntityType.Location, name="somewhere", source=source)
+        worker_version = WorkerVersion.objects.first()
+        entity_1 = self.corpus.entities.create(type=EntityType.Person, name="an entity", worker_version=worker_version)
+        entity_2 = self.corpus.entities.create(type=EntityType.Location, name="somewhere", worker_version=worker_version)
         self.es_mock.count.return_value = {'count': 2}
         self.es_mock.search.return_value = self.build_es_response([
             # Test the ES ordering is preserved by returning entities in non-alphabetical order
diff --git a/arkindex/documents/tests/test_transcriptions.py b/arkindex/documents/tests/test_transcriptions.py
index 7ff9d3a1e0ca7fb9b59128cc8d880502c22fdb01..619d9ae08ca099f7855f7b049d5478b44a8541d1 100644
--- a/arkindex/documents/tests/test_transcriptions.py
+++ b/arkindex/documents/tests/test_transcriptions.py
@@ -2,10 +2,9 @@ from django.urls import reverse
 from rest_framework import status
 
 from arkindex.dataimport.models import WorkerVersion
-from arkindex.documents.models import Corpus, DataSource
+from arkindex.documents.models import Corpus
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.users.models import User
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestTranscriptions(FixtureAPITestCase):
@@ -21,12 +20,12 @@ class TestTranscriptions(FixtureAPITestCase):
         cls.line = cls.corpus.elements.get(name='Text line')
         cls.private_corpus = Corpus.objects.create(name='Private')
         cls.private_page = cls.private_corpus.elements.create(type=cls.page.type)
-        cls.src = DataSource.objects.get(slug='test', type=MLToolType.Recognizer)
         # Create an user with a read right only on the private corpus
         cls.private_read_user = User.objects.create_user('a@bc.de', 'a')
         cls.private_read_user.verified_email = True
         cls.private_read_user.save()
-        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
+        cls.worker_version_1 = WorkerVersion.objects.get(worker__slug='reco')
+        cls.worker_version_2 = WorkerVersion.objects.get(worker__slug='dla')
 
     def test_list_transcriptions_read_right(self):
         # A read right on the element corpus is required to access transcriptions
@@ -39,7 +38,7 @@ class TestTranscriptions(FixtureAPITestCase):
         tr1 = self.page.transcriptions.get()
         tr2 = self.page.transcriptions.create(
             text='something',
-            worker_version=self.worker_version,
+            worker_version=self.worker_version_2,
             score=0.369,
         )
         self.client.force_login(self.user)
@@ -53,23 +52,14 @@ class TestTranscriptions(FixtureAPITestCase):
                 'id': str(tr1.id),
                 'text': 'Lorem ipsum dolor sit amet',
                 'score': 1.0,
-                'source': {
-                    'id': str(self.src.id),
-                    'type': 'recognizer',
-                    'slug': 'test',
-                    'name': 'Test Recognizer',
-                    'revision': '4.2',
-                    'internal': False,
-                },
-                'worker_version_id': None,
+                'worker_version_id': str(self.worker_version_1.id),
                 'element': None,
             },
             {
                 'id': str(tr2.id),
                 'text': 'something',
                 'score': 0.369,
-                'source': None,
-                'worker_version_id': str(self.worker_version.id),
+                'worker_version_id': str(self.worker_version_2.id),
                 'element': None,
             }
         ])
@@ -99,7 +89,7 @@ class TestTranscriptions(FixtureAPITestCase):
     def test_list_worker_version_transcriptions(self):
         worker_transcription = self.page.transcriptions.create(
             text='something',
-            worker_version=self.worker_version,
+            worker_version=self.worker_version_2,
             score=0.369,
         )
 
@@ -108,7 +98,7 @@ class TestTranscriptions(FixtureAPITestCase):
         with self.assertNumQueries(12):
             response = self.client.get(
                 reverse('api:element-transcriptions', kwargs={'pk': str(self.page.id)}),
-                data={'recursive': 'true', 'worker_version': str(self.worker_version.id)}
+                data={'recursive': 'true', 'worker_version': str(self.worker_version_2.id)}
             )
         self.assertEqual(response.status_code, status.HTTP_200_OK)
 
@@ -117,8 +107,7 @@ class TestTranscriptions(FixtureAPITestCase):
                 'id': str(worker_transcription.id),
                 'text': 'something',
                 'score': 0.369,
-                'source': None,
-                'worker_version_id': str(self.worker_version.id),
+                'worker_version_id': str(self.worker_version_2.id),
                 'element': {
                     'id': str(self.page.id),
                     'name': 'Volume 1, page 1r',
diff --git a/arkindex/project/api_v1.py b/arkindex/project/api_v1.py
index ac32f5af7f8d791c3cee725032de5714c361dd9b..1312bdc1b55c938e867cb87f2eeb170a16c304b9 100644
--- a/arkindex/project/api_v1.py
+++ b/arkindex/project/api_v1.py
@@ -71,8 +71,6 @@ from arkindex.documents.api.ml import (
     ClassificationReject,
     ClassificationValidate,
     CorpusMLClassList,
-    CorpusMLStats,
-    ElementMLStats,
     ElementTranscriptionsBulk,
     ManageClassificationsSelection,
     MLClassList,
@@ -131,7 +129,6 @@ api = [
         ElementTranscriptionsBulk.as_view(),
         name='element-transcriptions-bulk'
     ),
-    path('element/<uuid:pk>/ml-stats/', ElementMLStats.as_view(), name='element-ml-stats'),
     path('element/<uuid:child>/parent/<uuid:parent>/', ElementParent.as_view(), name='element-parent'),
 
     # Corpora
@@ -141,7 +138,6 @@ api = [
     path('corpus/<uuid:corpus>/elements/', CorpusElements.as_view(), name='corpus-elements'),
     path('corpus/<uuid:pk>/classes/', CorpusMLClassList.as_view(), name='corpus-classes'),
     path('corpus/<uuid:pk>/roles/', CorpusRoles.as_view(), name='corpus-roles'),
-    path('corpus/<uuid:pk>/ml-stats/', CorpusMLStats.as_view(), name='corpus-ml-stats'),
     path('corpus/<uuid:pk>/allowed-metadata/', CorpusAllowedMetaData.as_view(), name='corpus-allowed-metadata'),
     path('corpus/<uuid:pk>/versions/', CorpusWorkerVersionList.as_view(), name='corpus-versions'),
     path('corpus/<uuid:pk>/selection/', CorpusDeleteSelection.as_view(), name='corpus-delete-selection'),
diff --git a/arkindex/project/openapi/patch.yml b/arkindex/project/openapi/patch.yml
index 1aa64baee2a7baf4eef3a4afefd0c8608af2e77a..187025b3f9f9d46cf17b768ca81db1bb3ae16721 100644
--- a/arkindex/project/openapi/patch.yml
+++ b/arkindex/project/openapi/patch.yml
@@ -100,11 +100,6 @@ paths:
                     id: 55cd009d-cd4b-4ec2-a475-b060f98f9138
                     corpus:
                       - Role already exists in this corpus
-  /api/v1/corpus/{id}/ml-stats/:
-    delete:
-      # Will need https://gitlab.com/arkindex/backend/-/issues/86 to be removed
-      operationId: DestroyCorpusMLResults
-      description: Delete machine learning results on all elements of a corpus.
   /api/v1/element/{id}/:
     get:
       description: Retrieve a single element's informations and metadata
@@ -115,11 +110,6 @@ paths:
       description: Rename an element
     delete:
       description: Delete a childless element
-  /api/v1/element/{id}/ml-stats/:
-    delete:
-      # Will need https://gitlab.com/arkindex/backend/-/issues/86 to be removed
-      operationId: DestroyElementMLResults
-      description: Delete machine learning results on an element and its direct children.
   /api/v1/elements/{id}/children/:
     delete:
       operationId: DestroyElementChildren
diff --git a/arkindex/project/tests/test_elastic.py b/arkindex/project/tests/test_elastic.py
index 05565df4ec8e00c7ffa93ecedee78f10f20200ee..3a9da527cdd6aa2404319dbadad7ba6d24d4d2f1 100644
--- a/arkindex/project/tests/test_elastic.py
+++ b/arkindex/project/tests/test_elastic.py
@@ -1,11 +1,10 @@
 from unittest.mock import patch
 
+from arkindex.dataimport.models import WorkerVersion
 from arkindex.documents.dates import DateType, InterpretedDate
-from arkindex.documents.models import DataSource
 from arkindex.project.elastic import ESElement
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex_common.enums import MetaType
-from arkindex_common.ml_tool import MLToolType
 
 
 class TestESDocuments(FixtureAPITestCase):
@@ -61,7 +60,7 @@ class TestESDocuments(FixtureAPITestCase):
         surface.add_parent(page)
         surface.transcriptions.create(
             text='invisible transcription',
-            source=DataSource.objects.get(slug='test', type=MLToolType.Recognizer),
+            worker_version=WorkerVersion.objects.get(worker__slug='reco'),
         )
         texts = [tr['text'] for tr in ESElement.from_model(page).to_dict()['transcriptions']]
         self.assertNotIn('invisible transcription', texts)
diff --git a/arkindex/project/triggers.py b/arkindex/project/triggers.py
index 736a7f44b15a16c34a33d64b54072995c7db6552..a97585f846f5d472bda7dbc36008b653964a083d 100644
--- a/arkindex/project/triggers.py
+++ b/arkindex/project/triggers.py
@@ -76,46 +76,6 @@ def reindex_start(*,
     )
 
 
-def ml_results_delete(*,
-                      element: Union[Element, UUID, str] = None,
-                      corpus: Union[Corpus, UUID, str] = None,
-                      batch_size: int = 1000,
-                      user_id: Optional[int] = None) -> None:
-    """
-    Delete all ML results from all sources on a corpus
-    or an element and its *direct* (non-recursive) children.
-    """
-    element_id = None
-    corpus_id = None
-    if isinstance(element, Element):
-        element_id = str(element.id)
-    elif element:
-        element_id = str(element)
-
-    if isinstance(corpus, Corpus):
-        corpus_id = str(corpus.id)
-    elif corpus:
-        corpus_id = str(corpus)
-
-    assert element_id or corpus_id, 'Missing element or corpus ID'
-
-    if element_id:
-        description = f'ML results deletion on element {element_id}'
-    else:
-        description = f'ML results deletion on corpus {corpus_id}'
-
-    job = tasks.ml_results_delete.delay(
-        corpus_id=corpus_id,
-        element_id=element_id,
-        batch_size=batch_size,
-        description=description,
-        user_id=user_id,
-    )
-    if settings.ARKINDEX_FEATURES['search']:
-        # Trigger a reindex afterwards to cleanup the deleted results
-        tasks.reindex_start.delay(corpus_id=corpus_id, element_id=element_id, depends_on=job)
-
-
 def corpus_delete(corpus: Union[Corpus, UUID, str], user_id: Optional[int] = None) -> None:
     """
     Delete a whole corpus without killing a server by removing all related
diff --git a/arkindex/sql_validation/element_trash_children.sql b/arkindex/sql_validation/element_trash_children.sql
index e80795b9f401e3f005d909af8892f04a9df4a1ab..e03f175df9b87727a4a1cdedca83886ebfa715d9 100644
--- a/arkindex/sql_validation/element_trash_children.sql
+++ b/arkindex/sql_validation/element_trash_children.sql
@@ -112,7 +112,6 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 INNER JOIN "documents_elementpath" ON ("documents_element"."id" = "documents_elementpath"."element_id")
@@ -224,7 +223,6 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 INNER JOIN "documents_elementpath" ON ("documents_element"."id" = "documents_elementpath"."element_id")
@@ -304,7 +302,6 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 WHERE "documents_element"."id" = '{id}'::uuid;
diff --git a/arkindex/sql_validation/element_trash_deep.sql b/arkindex/sql_validation/element_trash_deep.sql
index fdc4ce048f1697102e5be945c88d6b688d24b396..dd5e994626cbfac9d5429184ebc0546b78588927 100644
--- a/arkindex/sql_validation/element_trash_deep.sql
+++ b/arkindex/sql_validation/element_trash_deep.sql
@@ -111,7 +111,6 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 INNER JOIN "documents_elementpath" ON ("documents_element"."id" = "documents_elementpath"."element_id")
@@ -223,7 +222,6 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 INNER JOIN "documents_elementpath" ON ("documents_element"."id" = "documents_elementpath"."element_id")
@@ -335,7 +333,6 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 INNER JOIN "documents_elementpath" ON ("documents_element"."id" = "documents_elementpath"."element_id")
@@ -447,7 +444,6 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 INNER JOIN "documents_elementpath" ON ("documents_element"."id" = "documents_elementpath"."element_id")
@@ -527,7 +523,6 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 WHERE "documents_element"."id" = '{id}'::uuid;
diff --git a/arkindex/sql_validation/element_trash_ml_class.sql b/arkindex/sql_validation/element_trash_ml_class.sql
index cfbbec2ecf79f6b8a4dd5659f6ab7b1b381abeb7..88be7fe32519fe90fcd0ec0378b47f971a1aacfb 100644
--- a/arkindex/sql_validation/element_trash_ml_class.sql
+++ b/arkindex/sql_validation/element_trash_ml_class.sql
@@ -120,7 +120,6 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 INNER JOIN "documents_elementpath" ON ("documents_element"."id" = "documents_elementpath"."element_id")
@@ -209,8 +208,7 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 INNER JOIN "documents_classification" ON ("documents_element"."id" = "documents_classification"."element_id")
-WHERE "documents_classification"."id" IS NOT NULL
\ No newline at end of file
+WHERE "documents_classification"."id" IS NOT NULL
diff --git a/arkindex/sql_validation/element_trash_no_children.sql b/arkindex/sql_validation/element_trash_no_children.sql
index 41b889a7bb33fbb69caeb4c4801535a03477a972..66f880696ca554cc7f8ddb5be95b1f0c7b17a063 100644
--- a/arkindex/sql_validation/element_trash_no_children.sql
+++ b/arkindex/sql_validation/element_trash_no_children.sql
@@ -69,7 +69,6 @@ SELECT "documents_element"."id",
        "documents_element"."type_id",
        "documents_element"."name",
        "documents_element"."zone_id",
-       "documents_element"."source_id",
        "documents_element"."worker_version_id"
 FROM "documents_element"
 WHERE "documents_element"."id" = '{id}'::uuid;