diff --git a/README.md b/README.md
index 1264739d218df74b44150ee3284bfc4c38b6d633..55e9805b1de6e94aa3027c7d8c362efc30b4dee0 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,14 @@
 # lustra-django-app
 
-## Running the Django server on Windows
+This micro-service is the API used by multiple micro-services in the infrastructure. It is used by the Grafana dashboard as a data source, by the MQTT Client as a data input and by the Godot game as both input and output.
+
+## Requirements
+
+Python >=3.11
+
+Other project dependencies are listed in the [`requirements.txt`](./requirements.txt) file.
+
+## Seting up the development environment
 
 Create a Python virtual environment.
 
@@ -10,11 +18,19 @@ python -m venv env
 
 Activate the virtual enviornment.
 
+- On Linux based systems
+
 ```
-env\Scripts\activate.bat
+source ./env/bin/activate
 ```
 
-Install the requirements.
+- On Windows
+
+```
+.\env\Scripts\activate
+```
+
+Install the requirements using pip.
 
 ```
 pip install -r requirements.txt
@@ -22,6 +38,8 @@ pip install -r requirements.txt
 
 Apply the database migrations.
 
+> By default, SQLite3 is used as a development database. Refer to Djang's documentation if you wish to modify the database driver used.
+
 ```
 python lustraDjangoApp\manage.py migrate
 ```
@@ -34,14 +52,9 @@ python lustraDjangoApp\manage.py runserver
 
 Run the server on default route.
 
-```
-python lustraDjangoApp\manage.py 0.0.0.0:8000
-```
+## API Documentation
 
-## Running the Django server with the launch script on Windows
+The API documentation is served on two endpoints after running the app:
 
-Run the `launch-script-windows.bat` through a terminal.
-
-```
-C:\...> launch-script-windows.bat
-```
+- `/api/schema/swagger-ui` using Swagger
+- `/api/schema/redoc` using Redoc
diff --git a/lustraDjangoApp/lustraApi/models.py b/lustraDjangoApp/lustraApi/models.py
index e28037b7c3b3e0aca63decf65cd309b22f99f430..f86ff3d098d4c3996568ddfcfd38333d1e19a790 100644
--- a/lustraDjangoApp/lustraApi/models.py
+++ b/lustraDjangoApp/lustraApi/models.py
@@ -4,10 +4,14 @@ from django.db import models
 
 
 class Message(models.Model):
+    """Messages that transit between the broker and the other micro-services.
+    """
     payload = models.JSONField()
 
 
 class RecyclingCounters(models.Model):
+    """Numerical counters used by the game.
+    """
     pet_counter = models.IntegerField()
     alu_counter = models.IntegerField()
     bad_recycling_counter = models.IntegerField(default=0)
@@ -15,17 +19,23 @@ class RecyclingCounters(models.Model):
 
 
 class UserFeedback(models.Model):
+    """Feedback send by the user when a recycling was deemed as a bad.
+    """
     container_type = models.IntegerField()
     is_system_wrong = models.BooleanField()
     timestamp = models.DateTimeField(auto_now_add=True)
 
 
 class DeviceMonitoringData(models.Model):
+    """Pings sent by the devices to monitor their activity.
+    """
     device_id = models.IntegerField()
     timestamp = models.DateTimeField(auto_now_add=True)
 
 
 class RecyclingData(models.Model):
+    """Recycling data class used primarly for showing data.
+    """
     device_id = models.IntegerField()
     container_type = models.IntegerField()
     game_code = models.BooleanField()
diff --git a/lustraDjangoApp/lustraApi/views.py b/lustraDjangoApp/lustraApi/views.py
index bf722e776821a77da74bb566f14b003298f5a02d..a834427b92c81e7f1991694dce030e44e0fb4a17 100644
--- a/lustraDjangoApp/lustraApi/views.py
+++ b/lustraDjangoApp/lustraApi/views.py
@@ -2,7 +2,11 @@ from lustraApi.models import Message, UserFeedback, RecyclingCounters, DeviceMon
 from lustraApi.serializers import MessagesSerializer, UserFeedbackSerializer, RecyclingCountersSerializer, DeviceMonitoringDataSerializer, RecyclingDataSerializer
 from rest_framework import viewsets, status
 from rest_framework.response import Response
+from rest_framework.request import Request
 from rest_framework.decorators import action
+from datetime import datetime
+from itertools import groupby
+import ciso8601
 
 # Create your views here.
 
@@ -11,6 +15,19 @@ class MessageViewSet(viewsets.ModelViewSet):
     queryset = Message.objects.all()
     serializer_class = MessagesSerializer
 
+    @action(detail=False, methods=["GET"], url_path='get-and-delete')
+    def get_and_delete(self, request):
+        """Retrieves and removes all messages.
+        """
+        try:
+            response = self.list(request=request)
+            messages = self.queryset.all()
+            for message in messages:
+                message.delete()
+            return response
+        except RecyclingCounters.DoesNotExist:
+            return Response(status=status.HTTP_404_NOT_FOUND)
+
 
 class UserFeedbackViewSet(viewsets.ModelViewSet):
     queryset = UserFeedback.objects.all()
@@ -21,10 +38,22 @@ class RecyclingCountersViewSet(viewsets.ModelViewSet):
     queryset = RecyclingCounters.objects.all()
     serializer_class = RecyclingCountersSerializer
 
+    def create(self, request: Request, *args, **kwargs):
+        response = self.latest(request)
+        if response.status_code == status.HTTP_200_OK:
+            if 'pet_counter' in response.data and 'alu_counter' in response.data and 'bad_recycling_counter' in response.data:
+                if request.data['pet_counter'] >= response.data['pet_counter'] and \
+                        request.data['alu_counter'] >= response.data['alu_counter'] and \
+                        request.data['bad_recycling_counter'] >= response.data['bad_recycling_counter']:
+                    return super().create(request, *args, **kwargs)
+        return Response(status=status.HTTP_204_NO_CONTENT)
+
     @action(
         detail=False, methods=["GET"], url_path="latest"
     )
     def latest(self, request):
+        """Returns the latest record in the database.
+        """
         try:
             latest_recycling_counters = self.queryset.latest('timestamp')
             serializer = self.get_serializer(latest_recycling_counters)
@@ -41,6 +70,8 @@ class DeviceMonitoringDataViewSet(viewsets.ModelViewSet):
         detail=False, methods=["GET"], url_path=r'latest/(?P<device_id>[^/.]+)'
     )
     def latest(self, request, device_id=None):
+        """Returns the latest record in the database.
+        """
         try:
             device_monitoring_data = self.queryset.filter(
                 device_id__exact=device_id).latest('timestamp')
@@ -53,3 +84,52 @@ class DeviceMonitoringDataViewSet(viewsets.ModelViewSet):
 class RecyclingDataViewSet(viewsets.ModelViewSet):
     queryset = RecyclingData.objects.all()
     serializer_class = RecyclingDataSerializer
+
+    @action(
+        detail=False, methods=["GET"], url_path='metrics'
+    )
+    def metrics(self, request):
+        """Get recycling data formatted in order to display it on a Grafana dashboard.
+
+        Each recycling data is grouped by day, which is extracted from the timestamp. The data is expanded with additional counters that are computed in order to sepearte good / bad recycling for PET / ALU.
+        """
+        recycling_data_list = list(self.queryset)
+
+        def transform_data(data):
+            serialized_data = self.get_serializer(data).data
+            serialized_data['timestamp'] = datetime.fromtimestamp(
+                serialized_data['timestamp']).strftime('%Y-%m-%d')
+            return serialized_data
+        transformed_data = map(transform_data, recycling_data_list)
+        grouped_by_timestamp_data = groupby(
+            transformed_data, lambda x: x['timestamp'])
+
+        return_data = list()
+        # Might need improving because this will be slow with a lot of data...
+        for key, value in grouped_by_timestamp_data:
+            good_pet_recycling = 0
+            good_alu_recycling = 0
+            bad_pet_recycling = 0
+            bad_alu_recycling = 0
+            for element in list(value):
+                if element['container_type'] == 0 and element['game_code']:
+                    good_pet_recycling += 1
+                elif element['container_type'] == 1 and element['game_code']:
+                    good_alu_recycling += 1
+                elif element['container_type'] == 0 and not element['game_code']:
+                    bad_pet_recycling += 1
+                elif element['container_type'] == 1 and not element['game_code']:
+                    bad_alu_recycling += 1
+            return_data.append(
+                {
+                    'good_pet_recycling': good_pet_recycling,
+                    'good_alu_recycling': good_alu_recycling,
+                    'bad_pet_recycling': bad_pet_recycling,
+                    'bad_alu_recycling': bad_alu_recycling,
+                    'total_pet_recycling': good_pet_recycling + bad_pet_recycling,
+                    'total_alu_recycling': good_alu_recycling + bad_alu_recycling,
+                    'time': ciso8601.parse_datetime(key).timestamp()
+                }
+            )
+
+        return Response(return_data)
diff --git a/lustraDjangoApp/lustraDjangoApp/settings.py b/lustraDjangoApp/lustraDjangoApp/settings.py
index b68e96efc04698cc8ab4aa377fe355fe8b08597d..282126023660d02da8738630130eaa2f2d8b8b36 100644
--- a/lustraDjangoApp/lustraDjangoApp/settings.py
+++ b/lustraDjangoApp/lustraDjangoApp/settings.py
@@ -48,6 +48,8 @@ INSTALLED_APPS = [
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'rest_framework',
+    'drf_spectacular',
+    'drf_spectacular_sidecar',
 ]
 
 MIDDLEWARE = [
@@ -130,7 +132,8 @@ AUTH_PASSWORD_VALIDATORS = [
 REST_FRAMEWORK = {
     'DEFAULT_RENDERER_CLASSES': (
         'rest_framework.renderers.JSONRenderer',
-    )
+    ),
+    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
 }
 
 # Internationalization
@@ -155,4 +158,14 @@ STATIC_ROOT = os.path.join(BASE_DIR, "static/")
 # Default primary key field type
 # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
 
-DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
+DEFAULT_AUTO_FIELD = 'django.db.models.Bi gAutoField'
+
+SPECTACULAR_SETTINGS = {
+    'TITLE': 'Lustra Django API',
+    'DESCRIPTION': 'This API serves as a data source for the Godot game and the Grafana dashboard, and as a data input for the information coming from the MQTT Broker.',
+    'VERSION': '1.0.0',
+    'SERVE_INCLUDE_SCHEMA': False,
+    'SWAGGER_UI_DIST': 'SIDECAR',  # shorthand to use the sidecar instead
+    'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
+    'REDOC_DIST': 'SIDECAR',
+}
diff --git a/lustraDjangoApp/lustraDjangoApp/urls.py b/lustraDjangoApp/lustraDjangoApp/urls.py
index 0f54d34027595f5ed65a1649f5e449175b4a5902..68786f8a58ab0f24ed4dbe782b9285d722d4d7be 100644
--- a/lustraDjangoApp/lustraDjangoApp/urls.py
+++ b/lustraDjangoApp/lustraDjangoApp/urls.py
@@ -14,10 +14,10 @@ Including another URLconf
     1. Import the include() function: from django.urls import include, path
     2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
 """
-from django.contrib import admin
 from rest_framework import routers
 from django.urls import path, include
 from lustraApi import views
+from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
 
 router = routers.DefaultRouter()
 router.register(r'messages', views.MessageViewSet)
@@ -29,5 +29,12 @@ router.register(r'recycling-data', views.RecyclingDataViewSet)
 
 urlpatterns = [
     path('', include(router.urls)),
+    # YOUR PATTERNS
+    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
+    # Optional UI:
+    path('api/schema/swagger-ui/',
+         SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
+    path('api/schema/redoc/',
+         SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
     # path('admin/', admin.site.urls),
 ]
diff --git a/lustraDjangoApp/schema.yml b/lustraDjangoApp/schema.yml
new file mode 100644
index 0000000000000000000000000000000000000000..271aa82e783d53837ee518300a46384eb11e2a69
--- /dev/null
+++ b/lustraDjangoApp/schema.yml
@@ -0,0 +1,1003 @@
+openapi: 3.0.3
+info:
+  title: Lustra Django API
+  version: 1.0.0
+  description: This API serves as a data source for the Godot
+    game and the Grafana dashboard, and as a data input for the information coming
+    from the MQTT Broker.
+paths:
+  /device-monitoring-data/:
+    get:
+      operationId: device_monitoring_data_list
+      tags:
+        - device-monitoring-data
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/DeviceMonitoringData"
+          description: ""
+    post:
+      operationId: device_monitoring_data_create
+      tags:
+        - device-monitoring-data
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/DeviceMonitoringData"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/DeviceMonitoringData"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/DeviceMonitoringData"
+        required: true
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "201":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DeviceMonitoringData"
+          description: ""
+  /device-monitoring-data/{id}/:
+    get:
+      operationId: device_monitoring_data_retrieve
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this device monitoring data.
+          required: true
+      tags:
+        - device-monitoring-data
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DeviceMonitoringData"
+          description: ""
+    put:
+      operationId: device_monitoring_data_update
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this device monitoring data.
+          required: true
+      tags:
+        - device-monitoring-data
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/DeviceMonitoringData"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/DeviceMonitoringData"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/DeviceMonitoringData"
+        required: true
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DeviceMonitoringData"
+          description: ""
+    patch:
+      operationId: device_monitoring_data_partial_update
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this device monitoring data.
+          required: true
+      tags:
+        - device-monitoring-data
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/PatchedDeviceMonitoringData"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/PatchedDeviceMonitoringData"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/PatchedDeviceMonitoringData"
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DeviceMonitoringData"
+          description: ""
+    delete:
+      operationId: device_monitoring_data_destroy
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this device monitoring data.
+          required: true
+      tags:
+        - device-monitoring-data
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "204":
+          description: No response body
+  /device-monitoring-data/latest/{device_id}/:
+    get:
+      operationId: device_monitoring_data_latest_retrieve
+      parameters:
+        - in: path
+          name: device_id
+          schema:
+            type: integer
+          required: true
+      tags:
+        - device-monitoring-data
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/DeviceMonitoringData"
+          description: ""
+  /messages/:
+    get:
+      operationId: messages_list
+      tags:
+        - messages
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/Messages"
+          description: ""
+    post:
+      operationId: messages_create
+      tags:
+        - messages
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/Messages"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/Messages"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/Messages"
+        required: true
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "201":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Messages"
+          description: ""
+  /messages/{id}/:
+    get:
+      operationId: messages_retrieve
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this message.
+          required: true
+      tags:
+        - messages
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Messages"
+          description: ""
+    put:
+      operationId: messages_update
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this message.
+          required: true
+      tags:
+        - messages
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/Messages"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/Messages"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/Messages"
+        required: true
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Messages"
+          description: ""
+    patch:
+      operationId: messages_partial_update
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this message.
+          required: true
+      tags:
+        - messages
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/PatchedMessages"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/PatchedMessages"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/PatchedMessages"
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Messages"
+          description: ""
+    delete:
+      operationId: messages_destroy
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this message.
+          required: true
+      tags:
+        - messages
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "204":
+          description: No response body
+  /messages/get-and-delete/:
+    get:
+      operationId: messages_get_and_delete_retrieve
+      tags:
+        - messages
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Messages"
+          description: ""
+  /recycling-counters/:
+    get:
+      operationId: recycling_counters_list
+      tags:
+        - recycling-counters
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/RecyclingCounters"
+          description: ""
+    post:
+      operationId: recycling_counters_create
+      tags:
+        - recycling-counters
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/RecyclingCounters"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/RecyclingCounters"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/RecyclingCounters"
+        required: true
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "201":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/RecyclingCounters"
+          description: ""
+  /recycling-counters/{id}/:
+    get:
+      operationId: recycling_counters_retrieve
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this recycling counters.
+          required: true
+      tags:
+        - recycling-counters
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/RecyclingCounters"
+          description: ""
+    put:
+      operationId: recycling_counters_update
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this recycling counters.
+          required: true
+      tags:
+        - recycling-counters
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/RecyclingCounters"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/RecyclingCounters"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/RecyclingCounters"
+        required: true
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/RecyclingCounters"
+          description: ""
+    patch:
+      operationId: recycling_counters_partial_update
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this recycling counters.
+          required: true
+      tags:
+        - recycling-counters
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/PatchedRecyclingCounters"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/PatchedRecyclingCounters"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/PatchedRecyclingCounters"
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/RecyclingCounters"
+          description: ""
+    delete:
+      operationId: recycling_counters_destroy
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this recycling counters.
+          required: true
+      tags:
+        - recycling-counters
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "204":
+          description: No response body
+  /recycling-counters/latest/:
+    get:
+      operationId: recycling_counters_latest_retrieve
+      tags:
+        - recycling-counters
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/RecyclingCounters"
+          description: ""
+  /recycling-data/:
+    get:
+      operationId: recycling_data_list
+      tags:
+        - recycling-data
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/RecyclingData"
+          description: ""
+    post:
+      operationId: recycling_data_create
+      tags:
+        - recycling-data
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/RecyclingData"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/RecyclingData"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/RecyclingData"
+        required: true
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "201":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/RecyclingData"
+          description: ""
+  /recycling-data/{id}/:
+    get:
+      operationId: recycling_data_retrieve
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this recycling data.
+          required: true
+      tags:
+        - recycling-data
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/RecyclingData"
+          description: ""
+    put:
+      operationId: recycling_data_update
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this recycling data.
+          required: true
+      tags:
+        - recycling-data
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/RecyclingData"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/RecyclingData"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/RecyclingData"
+        required: true
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/RecyclingData"
+          description: ""
+    patch:
+      operationId: recycling_data_partial_update
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this recycling data.
+          required: true
+      tags:
+        - recycling-data
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/PatchedRecyclingData"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/PatchedRecyclingData"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/PatchedRecyclingData"
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/RecyclingData"
+          description: ""
+    delete:
+      operationId: recycling_data_destroy
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this recycling data.
+          required: true
+      tags:
+        - recycling-data
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "204":
+          description: No response body
+  /recycling-data/metrics/:
+    get:
+      operationId: recycling_data_metrics_retrieve
+      tags:
+        - recycling-data
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/RecyclingData"
+          description: ""
+  /user-feedbacks/:
+    get:
+      operationId: user_feedbacks_list
+      tags:
+        - user-feedbacks
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/UserFeedback"
+          description: ""
+    post:
+      operationId: user_feedbacks_create
+      tags:
+        - user-feedbacks
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/UserFeedback"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/UserFeedback"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/UserFeedback"
+        required: true
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "201":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/UserFeedback"
+          description: ""
+  /user-feedbacks/{id}/:
+    get:
+      operationId: user_feedbacks_retrieve
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this user feedback.
+          required: true
+      tags:
+        - user-feedbacks
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/UserFeedback"
+          description: ""
+    put:
+      operationId: user_feedbacks_update
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this user feedback.
+          required: true
+      tags:
+        - user-feedbacks
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/UserFeedback"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/UserFeedback"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/UserFeedback"
+        required: true
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/UserFeedback"
+          description: ""
+    patch:
+      operationId: user_feedbacks_partial_update
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this user feedback.
+          required: true
+      tags:
+        - user-feedbacks
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/PatchedUserFeedback"
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: "#/components/schemas/PatchedUserFeedback"
+          multipart/form-data:
+            schema:
+              $ref: "#/components/schemas/PatchedUserFeedback"
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/UserFeedback"
+          description: ""
+    delete:
+      operationId: user_feedbacks_destroy
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this user feedback.
+          required: true
+      tags:
+        - user-feedbacks
+      security:
+        - cookieAuth: []
+        - basicAuth: []
+        - {}
+      responses:
+        "204":
+          description: No response body
+components:
+  schemas:
+    DeviceMonitoringData:
+      type: object
+      properties:
+        device_id:
+          type: integer
+        timestamp:
+          type: string
+          format: date-time
+          readOnly: true
+      required:
+        - device_id
+        - timestamp
+    Messages:
+      type: object
+      properties:
+        id:
+          type: integer
+          readOnly: true
+        payload: {}
+      required:
+        - id
+        - payload
+    PatchedDeviceMonitoringData:
+      type: object
+      properties:
+        device_id:
+          type: integer
+        timestamp:
+          type: string
+          format: date-time
+          readOnly: true
+    PatchedMessages:
+      type: object
+      properties:
+        id:
+          type: integer
+          readOnly: true
+        payload: {}
+    PatchedRecyclingCounters:
+      type: object
+      properties:
+        id:
+          type: integer
+          readOnly: true
+        pet_counter:
+          type: integer
+        alu_counter:
+          type: integer
+        bad_recycling_counter:
+          type: integer
+        timestamp:
+          type: string
+          format: date-time
+          readOnly: true
+    PatchedRecyclingData:
+      type: object
+      properties:
+        device_id:
+          type: integer
+        container_type:
+          type: integer
+        game_code:
+          type: boolean
+        sensors: {}
+        wav_file:
+          type: string
+        bin_file:
+          type: string
+        timestamp:
+          type: number
+          format: double
+    PatchedUserFeedback:
+      type: object
+      properties:
+        id:
+          type: integer
+          readOnly: true
+        container_type:
+          type: integer
+        is_system_wrong:
+          type: boolean
+        timestamp:
+          type: string
+          format: date-time
+          readOnly: true
+    RecyclingCounters:
+      type: object
+      properties:
+        id:
+          type: integer
+          readOnly: true
+        pet_counter:
+          type: integer
+        alu_counter:
+          type: integer
+        bad_recycling_counter:
+          type: integer
+        timestamp:
+          type: string
+          format: date-time
+          readOnly: true
+      required:
+        - alu_counter
+        - id
+        - pet_counter
+        - timestamp
+    RecyclingData:
+      type: object
+      properties:
+        device_id:
+          type: integer
+        container_type:
+          type: integer
+        game_code:
+          type: boolean
+        sensors: {}
+        wav_file:
+          type: string
+        bin_file:
+          type: string
+        timestamp:
+          type: number
+          format: double
+      required:
+        - bin_file
+        - container_type
+        - device_id
+        - game_code
+        - sensors
+        - timestamp
+        - wav_file
+    UserFeedback:
+      type: object
+      properties:
+        id:
+          type: integer
+          readOnly: true
+        container_type:
+          type: integer
+        is_system_wrong:
+          type: boolean
+        timestamp:
+          type: string
+          format: date-time
+          readOnly: true
+      required:
+        - container_type
+        - id
+        - is_system_wrong
+        - timestamp
+  securitySchemes:
+    basicAuth:
+      type: http
+      scheme: basic
+    cookieAuth:
+      type: apiKey
+      in: cookie
+      name: sessionid
diff --git a/requirements.txt b/requirements.txt
index b78b20bf4fddad6b30e5798cacafed2e3f21f39a..9452eeeb7b6864e6adf97164267fb9646343bc6c 100644
Binary files a/requirements.txt and b/requirements.txt differ