diff --git a/django/api/__init__.py b/django/api/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/django/api/apps.py b/django/api/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..f1d64a8f188de61f39d2b5c7d91427c0c27df249
--- /dev/null
+++ b/django/api/apps.py
@@ -0,0 +1,12 @@
+"""
+    Default setted file from django for an added app.
+"""
+
+from django.apps import AppConfig
+
+
+class ApiConfig(AppConfig):
+    """Default setted SharedModelsConfig class for the app.
+    """
+    default_auto_field = "django.db.models.BigAutoField"
+    name = "api"
diff --git a/django/api/urls.py b/django/api/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..592c29ff3ef136da77d206cf9521c9bcad8da958
--- /dev/null
+++ b/django/api/urls.py
@@ -0,0 +1,13 @@
+"""
+    File for setting the URLs used from the api django app.
+"""
+
+from django.urls import path
+from . import views
+
+
+urlpatterns = [
+    path('box/search', views.ButtonBoxSearchView.as_view(), name='box_search'),
+    path('box/use', views.ButtonBoxUseView.as_view(), name='box_use'),
+    path('box/use/count', views.ButtonBoxUseCountView.as_view(), name='box_use_count'),
+]
diff --git a/django/api/views.py b/django/api/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..aaeea0da7719c25b6bab7d012322b88673d8584d
--- /dev/null
+++ b/django/api/views.py
@@ -0,0 +1,442 @@
+"""
+    File for setting the view classes used from the api django app.
+"""
+
+from datetime import datetime, timezone
+
+from shared_models.models import ButtonBox, ButtonBoxUse
+from shared_models.serializers import ButtonBoxSerializer, ButtonBoxUseSerializer
+
+from rest_framework import status
+from rest_framework.response import Response
+from rest_framework.views import APIView
+from rest_framework.renderers import JSONRenderer
+from rest_framework_simplejwt.authentication import JWTAuthentication
+
+
+###
+### HELPERS
+###
+def helper_get_from_parsed(parsed_name: str, parsed_value: str, parsed_type: str):
+    """Helper method used from the ButtonBoxUseView class for setting the return values from different 'parsed_name' and 'parsed_type'.
+    It will fetch or update the values from the ButtonBoxUse model.
+
+    Parameters
+    ----------
+    parsed_name: str
+        String with the name parsed.
+    parsed_value: str
+        String with the value parsed.
+    parsed_type: str
+        String with the type parsed.
+
+    Returns
+    -------
+    ret_dict: dict
+        The Dictionary with the output from executing this helper method.
+    ret_status: rest_framework.status
+        The HTTP status from executing this helper method.
+    """
+
+    founded_box = None
+    ret_dict = None
+    ret_status = status.HTTP_500_INTERNAL_SERVER_ERROR
+    try:
+        if parsed_name == "id":
+            founded_box = ButtonBox.objects.get(id=parsed_value)
+
+        elif parsed_name == "name":
+            founded_box = ButtonBox.objects.get(name=parsed_value)
+
+        elif parsed_name == "pin_button":
+            founded_box = ButtonBox.objects.get(pin_button=parsed_value)
+
+        elif parsed_name == "pin_led":
+            founded_box = ButtonBox.objects.get(pin_led=parsed_value)
+
+        else:
+            ret_dict = {
+                'error': True,
+                'error_msg': f"ERROR: unknown parameter parsed: {parsed_name}."
+            }
+            ret_status = status.HTTP_406_NOT_ACCEPTABLE
+
+    except ButtonBox.DoesNotExist:
+        ret_dict = {
+            'error': True,
+            'error_msg': f"No Box could be founded with the '{parsed_name}': {parsed_value}"
+        }
+        ret_status = status.HTTP_404_NOT_FOUND
+
+    except Exception as e:
+        ret_dict = {
+            'error': True,
+            'error_msg': f"ERROR happend when trying to search for the box with {parsed_name}: {parsed_value} | Error: {e}"
+        }
+        ret_status = status.HTTP_406_NOT_ACCEPTABLE
+
+    ### If error ocurred, finish
+    if ret_dict is not None:
+        pass
+
+    else:
+        if parsed_type == "add":
+            try:
+                ### Add pushed from pin
+                added = ButtonBoxUse(box_used=founded_box)
+                added.save()
+
+                ret_dict = {
+                    'error': False,
+                    'message': "Added button press",
+                    "button-used": {
+                        "id": added.id,
+                        "box_id": added.box_used.id,
+                        'box_name': added.box_used.name,
+                        'box_pin_button': added.box_used.pin_button,
+                        'box_pin_led': added.box_used.pin_led,
+                        'date': str(added.date)
+                    }
+                }
+                ret_status = status.HTTP_200_OK
+
+
+            except Exception as e:
+                ret_dict = {
+                    'error': True,
+                    'message': f"Error saving the press button with output: {e}",
+                }
+                ret_status = status.HTTP_418_IM_A_TEAPOT
+
+        elif parsed_type == "list":
+            try:
+                ### Get list pushed button
+                box_uses = ButtonBoxUse.objects.filter(box_used=founded_box)
+                serializer = ButtonBoxUseSerializer(box_uses, many=True)
+                ret_dict = serializer.data
+                ret_status = status.HTTP_200_OK
+
+            except Exception as e:
+                ret_dict = {
+                    'error': True,
+                    'error_msg': f"ERROR happend when trying to search for the box with {parsed_name}: {parsed_value} | Error: {e}"
+                }
+                ret_status = status.HTTP_406_NOT_ACCEPTABLE
+
+        else:
+            ret_dict = {
+                'error': True,
+                'error_msg': "ERROR parsing response from 'helper_get_from_parsed' function"
+            }
+            ret_status = status.HTTP_501_NOT_IMPLEMENTED
+
+    return ret_dict, ret_status
+
+
+###
+### VIEW CLASSES
+###
+class ButtonBoxSearchView(APIView):
+    """Class for setting the API views for Searching at the ButtonBox model.
+    """
+
+    # permission_classes = [IsAuthenticated]
+    authentication_classes = [JWTAuthentication]
+    renderer_classes = [JSONRenderer]
+
+    def get(self, request, format=None):
+        """Method for dealing with the GET requests done at this view.
+
+        Parameters
+        ----------
+        request: rest_framework.request.Request
+            The parameters from the GET request.
+        format: None
+            If some format was sent.
+
+        Returns
+        -------
+        rest_framework.response.Response
+            The response object.
+        """
+        # Get parsed
+        box_id = request.query_params.get("id")
+        box_name = request.query_params.get("name")
+        box_pin_button = request.query_params.get("pin_button")
+        box_pin_led = request.query_params.get("pin_led")
+
+        if box_id is not None and box_name is None and box_pin_button is None and box_pin_led is None:
+            box_founded = ButtonBox.objects.filter(id__icontains=box_id)
+
+        elif box_id is None and box_name is not None and box_pin_button is None and box_pin_led is None:
+            box_founded = ButtonBox.objects.filter(name__icontains=box_name)
+
+        elif box_id is None and box_name is None and box_pin_button is not None and box_pin_led is None:
+            box_founded = ButtonBox.objects.filter(pin_button__icontains=box_pin_button)
+
+        elif box_id is None and box_name is None and box_pin_button is None and box_pin_led is not None:
+            box_founded = ButtonBox.objects.filter(pin_led__icontains=box_pin_led)
+
+        # If not, return all
+        else:
+            box_founded = ButtonBox.objects.all()
+
+        serializer = ButtonBoxSerializer(box_founded, many=True)
+
+        return Response(serializer.data, status=status.HTTP_200_OK)
+
+
+class ButtonBoxUseView(APIView):
+    """Class for setting the API views for Searching and Adding values at the ButtonBoxUse model.
+    """
+
+    # permission_classes = [IsAuthenticated]
+    authentication_classes = [JWTAuthentication]
+    renderer_classes = [JSONRenderer]
+
+    def get(self, request, format=None):
+        """Method for dealing with the GET requests done at this view.
+
+        Parameters
+        ----------
+        request: rest_framework.request.Request
+            The parameters from the GET request.
+        format: None
+            If some format was sent.
+
+        Returns
+        -------
+        rest_framework.response.Response
+            The response object.
+        """
+
+        # Get parsed
+        box_id = request.query_params.get("id")
+        box_name = request.query_params.get("name")
+        box_pin_button = request.query_params.get("pin_button")
+        box_pin_led = request.query_params.get("pin_led")
+
+        if box_id is not None and box_name is None and box_pin_button is None and box_pin_led is None:
+            founded_box = ButtonBox.objects.get(id=box_id)
+
+        elif box_id is None and box_name is not None and box_pin_button is None and box_pin_led is None:
+            founded_box = ButtonBox.objects.get(name=box_name)
+
+        elif box_id is None and box_name is None and box_pin_button is not None and box_pin_led is None:
+            founded_box = ButtonBox.objects.get(pin_button=box_pin_button)
+
+        elif box_id is None and box_name is None and box_pin_button is None and box_pin_led is not None:
+            founded_box = ButtonBox.objects.get(pin_led=box_pin_led)
+
+        else:
+            founded_box = None
+
+        # Get from parsed, if None get all
+        if founded_box is None:
+            boxes_uses = ButtonBoxUse.objects.all()
+            serializer = ButtonBoxUseSerializer(boxes_uses, many=True)
+
+        else:
+            box_uses = ButtonBoxUse.objects.filter(box_used=founded_box)
+            serializer = ButtonBoxUseSerializer(box_uses, many=True)
+
+        return Response(serializer.data, status=status.HTTP_200_OK)
+
+    def post(self, request, format=None):
+        """Method for dealing with the POST requests done at this view.
+
+        Parameters
+        ----------
+        request: rest_framework.request.Request
+            The parameters from the POST request.
+        format: None
+            If some format was sent.
+
+        Returns
+        -------
+        rest_framework.response.Response
+            The response object.
+        """
+        # Get the box name from the query parameters (if Nonne, default to empty str)
+        parsed_id = request.data.get("id")
+        parsed_name = request.data.get("name")
+        # parsed_pin_number = request.data.get("pin_number")
+        parsed_pin_button = request.data.get("pin_button")
+        parsed_pin_led = request.data.get("pin_led")
+
+        if parsed_id is None and parsed_name is None and parsed_pin_button is None and parsed_pin_led is None:
+            ret_dict = {
+                "error": True,
+                "message": "Unable to add box used from this end-point withtout parsed info from 'name', 'pin_button' or 'pin_led'"
+            }
+            ret_status = status.HTTP_400_BAD_REQUEST
+
+        elif parsed_id is not None and parsed_name is not None and parsed_pin_button is not None and parsed_pin_led is not None:
+            ret_dict = {
+                "error": True,
+                "message": "Unable to add box used from this end-point with MULTIPLE parsed infos from 'id', 'name', 'pin_button' and 'pin_led'. Use only one"
+            }
+            ret_status = status.HTTP_400_BAD_REQUEST
+
+        ### ID
+        elif parsed_id is not None and parsed_name is None and parsed_pin_button is None and parsed_pin_led is None:
+            ret_dict, ret_status = helper_get_from_parsed(
+                parsed_name='id',
+                parsed_value=parsed_id,
+                parsed_type='add'
+            )
+
+        ### NAME
+        elif parsed_name is not None and parsed_pin_button is None and parsed_pin_led is None:
+            ret_dict, ret_status = helper_get_from_parsed(
+                parsed_name='name',
+                parsed_value=parsed_name,
+                parsed_type='add'
+            )
+
+        ### PIN_BUTTON
+        elif parsed_name is None and parsed_pin_button is not None and parsed_pin_led is None:
+            ret_dict, ret_status = helper_get_from_parsed(
+                parsed_name='pin_button',
+                parsed_value=parsed_pin_button,
+                parsed_type='add'
+            )
+
+        ### PIN_LED
+        elif parsed_name is None and parsed_pin_button is None and parsed_pin_led is not None:
+            ret_dict, ret_status = helper_get_from_parsed(
+                parsed_name='pin_led',
+                parsed_value=parsed_pin_led,
+                parsed_type='add'
+            )
+
+        else:
+            ret_dict = {
+                "error": True,
+                "message": "Option not implemented..."
+            }
+            ret_status = status.HTTP_501_NOT_IMPLEMENTED
+
+        return Response(ret_dict, status=ret_status)
+
+
+class ButtonBoxUseCountView(APIView):
+    """Class for setting the API views for getting the amount of uses from a Button Box.
+    It is mostly used from Grafana for getting the fancy requests from date windows.
+    """
+
+    # permission_classes = [IsAuthenticated]
+    authentication_classes = [JWTAuthentication]
+    renderer_classes = [JSONRenderer]
+
+    def get(self, request, format=None):
+        """Method for dealing with the GET requests done at this view.
+
+        Parameters
+        ----------
+        request: rest_framework.request.Request
+            The parameters from the GET request.
+        format: None
+            If some format was sent.
+
+        Returns
+        -------
+        rest_framework.response.Response
+            The response object.
+        """
+
+        ###
+        ### EXAMPLE of the grafana used URL ;)
+        ###
+        ### http://localhost:8000/api/box/use/count?from=${__from}&to=${__to}
+        ###
+
+        ### GET PARSED
+        query_param_from = request.query_params.get("from")
+        query_param_to = request.query_params.get("to")
+
+        if query_param_from is not None and query_param_to is None:
+            ret_list = [
+                {
+                    'error': True,
+                    'error_msg': "Query parameter for 'from' is parsed and 'to' is not parsed. You have to use BOUTH or NONE"
+                }
+            ]
+            ret_status = status.HTTP_400_BAD_REQUEST
+
+        elif query_param_from is None and query_param_to is not None:
+            ret_list = [
+                {
+                    'error': True,
+                    'error_msg': "Query parameter for 'to' is parsed and 'from' is not parsed. You have to use BOUTH or NONE"
+                }
+            ]
+            ret_status = status.HTTP_400_BAD_REQUEST
+
+        ### RETURN ALL
+        elif query_param_from is None and query_param_to is None:
+
+            ret_list = []
+            for button_box in ButtonBox.objects.all():
+                ret_list.append(
+                    {
+                        "name": button_box.name,
+                        "count": ButtonBoxUse.objects.filter(box_used=button_box).count()
+                    }
+                )
+
+            ret_status = status.HTTP_200_OK
+
+        ### RETURN FROM TIME FRAME
+        elif query_param_from is not None and query_param_to is not None:
+
+            try:
+                date_from = datetime.fromtimestamp(int(query_param_from) / 1000, timezone.utc)
+
+            except Exception as e:
+                ret_list = [
+                    {
+                        'error': True,
+                        'error_msg': f"Error parsing epoch time to datetime from parsed 'date_from' parameter with error: {e}"
+                    }
+                ]
+                ret_status = status.HTTP_400_BAD_REQUEST
+
+            try:
+                date_to = datetime.fromtimestamp(int(query_param_to) / 1000, timezone.utc)
+
+            except Exception as e:
+                ret_list = [
+                    {
+                        'error': True,
+                        'error_msg': f"Error parsing epoch time to datetime from parsed 'date_to' parameter with error: {e}"
+                    }
+                ]
+                ret_status = status.HTTP_400_BAD_REQUEST
+
+            ret_list = []
+            for button_box in ButtonBox.objects.all():
+                button_name = button_box.name
+                count = 0
+                for button_use in ButtonBoxUse.objects.filter(date__gt=date_from, date__lt=date_to):
+                    if button_name == button_use.box_name:
+                        count += 1
+                        ret_list.append(
+                            {
+                                "name": button_name,
+                                "count": count,
+                                "date": button_use.date
+                            }
+                        )
+            ret_status = status.HTTP_200_OK
+
+        else:
+            ret_list = [
+                {
+                    'error': True,
+                    'error_msg': "Not implemented"
+                }
+            ]
+            ret_status = status.HTTP_501_NOT_IMPLEMENTED
+
+        return Response(ret_list, status=ret_status)
diff --git a/django/api_admin/__init__.py b/django/api_admin/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/django/api_admin/apps.py b/django/api_admin/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc61874d842807701326a0787bfe612b44c2d611
--- /dev/null
+++ b/django/api_admin/apps.py
@@ -0,0 +1,12 @@
+"""
+    Default setted file from django for an added app.
+"""
+
+from django.apps import AppConfig
+
+
+class ApiAdminConfig(AppConfig):
+    """Default setted SharedModelsConfig class for the app.
+    """
+    default_auto_field = "django.db.models.BigAutoField"
+    name = "api_admin"
diff --git a/django/api_admin/urls.py b/django/api_admin/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..6301cd4dd26e485cece9e9612421c1c76856555b
--- /dev/null
+++ b/django/api_admin/urls.py
@@ -0,0 +1,13 @@
+"""
+    File for setting the URLs used from the api_admin django app.
+"""
+
+from django.urls import path
+from . import views
+
+
+urlpatterns = [
+    path('box', views.AdminButtonBoxListCreateDeleteView.as_view(), name='admin_box'),
+    path('box/edit/<int:pk>', views.AdminButtonBoxRetrieveUpdateDestroyView.as_view(), name='admin_box_edit'),
+    path('box/use', views.AdminButtonBoxUseListCreateView.as_view(), name='admin_box_use'),
+]
diff --git a/django/api_admin/views.py b/django/api_admin/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..cc8d154045a4c7fafe3d493932e0243733ad149f
--- /dev/null
+++ b/django/api_admin/views.py
@@ -0,0 +1,76 @@
+"""
+    File for setting the view classes used from the api_admin django app.
+"""
+
+
+from shared_models.models import ButtonBox, ButtonBoxUse
+from shared_models.serializers import ButtonBoxSerializer, ButtonBoxUseSerializer
+from rest_framework import generics, status
+from rest_framework.response import Response
+from rest_framework.permissions import IsAuthenticated
+
+from backend.settings import DEFAULT_DJANGO_DEBUG
+
+
+class AdminButtonBoxListCreateDeleteView(generics.ListCreateAPIView):
+    """Class for setting the API views for Create, Read and Delete the entries at the ButtonBox model.
+    """
+
+    permission_classes = [IsAuthenticated]
+
+    queryset = ButtonBox.objects.all()
+    serializer_class = ButtonBoxSerializer
+
+    def delete(self, request, *args, **kwargs):
+        """Method for deleting all ButtonBox model objects.
+        """
+
+        # Delete only by debug mode
+        if DEFAULT_DJANGO_DEBUG:
+            ButtonBox.objects.all().delete()
+            return Response(status=status.HTTP_204_NO_CONTENT)
+        
+        else:
+            ret_dict = {
+                "error": False,
+                "message": "You can only delete all in debub mode --> set the 'DEFAULT_DJANGO_DEBUG' to 'True'"
+            }
+            return Response(ret_dict, status=status.HTTP_412_PRECONDITION_FAILED)
+
+
+class AdminButtonBoxRetrieveUpdateDestroyView(generics.RetrieveUpdateDestroyAPIView):
+    """Class for setting the API views for Updating entries at the ButtonBox model.
+    """
+
+    permission_classes = [IsAuthenticated]
+
+    queryset = ButtonBox.objects.all()
+    serializer_class = ButtonBoxSerializer
+    ### pk --> primary_key
+    lookup_field = "pk"
+
+
+class AdminButtonBoxUseListCreateView(generics.ListCreateAPIView):
+    """Class for setting the API views for Creating entries at the ButtonBoxUse model.
+    """
+
+    permission_classes = [IsAuthenticated]
+
+    queryset = ButtonBoxUse.objects.all()
+    serializer_class = ButtonBoxUseSerializer
+
+    def delete(self, request, *args, **kwargs):
+        """Method for deleting all ButtonBoxUse model objects.
+        """
+
+        # Delete only by debug mode
+        if DEFAULT_DJANGO_DEBUG:
+            ButtonBoxUse.objects.all().delete()
+            return Response(status=status.HTTP_204_NO_CONTENT)
+        
+        else:
+            ret_dict = {
+                "error": False,
+                "message": "You can only delete all in debub mode --> set the 'DEFAULT_DJANGO_DEBUG' to 'True'"
+            }
+            return Response(ret_dict, status=status.HTTP_412_PRECONDITION_FAILED)
diff --git a/django/api_auth/__init__.py b/django/api_auth/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/django/api_auth/apps.py b/django/api_auth/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..0d4e91be1a4ff0c2e01c06b07713971624c9c76e
--- /dev/null
+++ b/django/api_auth/apps.py
@@ -0,0 +1,12 @@
+"""
+    Default setted file from django for an added app.
+"""
+
+from django.apps import AppConfig
+
+
+class ApiAuthConfig(AppConfig):
+    """Default setted SharedModelsConfig class for the app.
+    """
+    default_auto_field = "django.db.models.BigAutoField"
+    name = "api_auth"
diff --git a/django/api_auth/templates/login.html b/django/api_auth/templates/login.html
new file mode 100644
index 0000000000000000000000000000000000000000..f7980935c847dcdf75a8e0fca18804d6585c8248
--- /dev/null
+++ b/django/api_auth/templates/login.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <title>Login</title>
+</head>
+
+<body>
+    <h2>Login</h2>
+    {% if user.is_authenticated %}
+        <p>Logged in as {{ user.username }}</p>
+        <a href="{% url 'logout' %}">Logout</a>
+    {% else %}
+        <p>You are not logged in.</p>
+    {% endif %}
+    <form method="post">
+        {% csrf_token %}
+        {{ form.as_p }}
+        <button type="submit">Login</button>
+    </form>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/django/api_auth/templates/logout.html b/django/api_auth/templates/logout.html
new file mode 100644
index 0000000000000000000000000000000000000000..71a9b56cb2007d0b2b39b2a95e1fa16aac9c065c
--- /dev/null
+++ b/django/api_auth/templates/logout.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <title>Logout</title>
+</head>
+
+<body>
+    <h2>You have been logged out.</h2>
+    <a href="{% url 'login' %}">Log in again</a>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/django/api_auth/urls.py b/django/api_auth/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..a7872fb30fd2fc82ba1e9cb1ab155f3edddafe44
--- /dev/null
+++ b/django/api_auth/urls.py
@@ -0,0 +1,22 @@
+"""
+    File for setting the URLs used from the api_auth django app.
+"""
+
+### TOKEN
+from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
+
+### LOGIN
+from django.contrib.auth import views as auth_views
+
+from django.urls import path
+from . import views
+
+
+urlpatterns = [
+    path('test/open', views.TestOpenView.as_view(), name='test-open'),
+    path('test/closed', views.TestClosedView.as_view(), name='test-closed'),
+    path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'),
+    path('logout/', views.custom_logout, name='logout'),
+    path("token/", TokenObtainPairView.as_view(), name='token_obtain_pair'),
+    path("token/refresh/", TokenRefreshView.as_view(), name='token_refresh'),
+]
diff --git a/django/api_auth/views.py b/django/api_auth/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..1946c4f29282833c8d41bae9dc554abcca95a51a
--- /dev/null
+++ b/django/api_auth/views.py
@@ -0,0 +1,97 @@
+
+"""
+TODO: Add this !!!
+"""
+from rest_framework import status
+from rest_framework.views import APIView
+from rest_framework import permissions
+# from rest_framework.permissions import IsAuthenticated
+from rest_framework.renderers import JSONRenderer
+from rest_framework_simplejwt.authentication import JWTAuthentication
+from django.views.decorators.http import require_GET
+from django.contrib.auth import logout
+from django.shortcuts import redirect
+from django.http import JsonResponse
+
+
+class TestOpenView(APIView):
+    """Class for testing an end-point without authentication.
+    """
+
+    permission_classes = [permissions.AllowAny]
+
+    def get(self, request=None, format=None):
+        """Method for dealing with the GET requests done at this view.
+
+        Parameters
+        ----------
+        request: rest_framework.request.Request
+            The parameters from the GET request.
+        format: None
+            If some format was sent.
+
+        Returns
+        -------
+        rest_framework.response.Response
+            The response object.
+        """
+
+        ret_dict = {
+            "error": False,
+            "message": "This is the auth test open end-point"
+        }
+
+        return JsonResponse(ret_dict, status=status.HTTP_200_OK)
+
+
+class TestClosedView(APIView):
+    """Class for testing the authentication.
+    """
+
+    # permission_classes = [IsAuthenticated]
+    authentication_classes = [JWTAuthentication]
+    renderer_classes = [JSONRenderer]
+
+    def get(self, request=None, format=None):
+        """Method for dealing with the GET requests done at this view.
+
+        Parameters
+        ----------
+        request: rest_framework.request.Request
+            The parameters from the GET request.
+        format: None
+            If some format was sent.
+
+        Returns
+        -------
+        rest_framework.response.Response
+            The response object.
+        """
+
+        ret_dict = {
+            "error": False,
+            "message": "You are authenticated"
+        }
+
+        return JsonResponse(ret_dict, status=status.HTTP_200_OK)
+
+
+# from rest_framework.response import Response
+@require_GET
+def custom_logout(request):
+    """Method for logging out from django.
+
+    Parameters
+    ----------
+    request: rest_framework.request.Request
+        The parameters from the GET request.
+
+    Returns
+    -------
+    redirect:
+        Redirects to the login page.
+    """
+
+    logout(request)
+    # return HttpResponse("You have been logged out.")  # Temporary for debugging
+    return redirect('/auth/login/')
diff --git a/django/backend/__init__.py b/django/backend/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/django/backend/asgi.py b/django/backend/asgi.py
new file mode 100644
index 0000000000000000000000000000000000000000..20e4b4470f67aecfe8eb8d6c6bcb481761221224
--- /dev/null
+++ b/django/backend/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for backend project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
+
+application = get_asgi_application()
diff --git a/django/backend/settings.py b/django/backend/settings.py
new file mode 100644
index 0000000000000000000000000000000000000000..146db36841427d710d59a49bd36776c386a2a982
--- /dev/null
+++ b/django/backend/settings.py
@@ -0,0 +1,212 @@
+"""
+Django settings for myproject project.
+
+Generated by 'django-admin startproject' using Django 5.1.6.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/5.1/ref/settings/
+"""
+import os
+from pathlib import Path
+from datetime import timedelta
+from dotenv import load_dotenv
+
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = "django-insecure-9^f+%n36vxg-^q-iu1$x4&+--&u+i4ds@!xhe@+i8w(-wg00bu"
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+# ALLOWED_HOSTS = []
+ALLOWED_HOSTS = ['*']
+
+###
+### LOAD VARIABLES
+###
+
+# Try loading from the .env file, if it exists...
+load_dotenv()
+
+try:
+    DEFAULT_TOKEN_EXPIRE_MIN = int(os.getenv("DEFAULT_TOKEN_EXPIRE_MIN"))
+
+except Exception:
+    DEFAULT_TOKEN_EXPIRE_MIN = 10080
+
+try:
+    DEFAULT_TOKEN_REFRESH_DAYS = int(os.getenv("DEFAULT_TOKEN_REFRESH_DAYS"))
+
+except Exception:
+    DEFAULT_TOKEN_REFRESH_DAYS = 7
+
+try:
+    fetched = int(os.getenv("DEFAULT_DJANGO_DEBUG"))
+    if fetched in ('YES', 'yes', 'true', 'True', 'TRUE'):
+        DEFAULT_DJANGO_DEBUG = True
+    else:
+        DEFAULT_DJANGO_DEBUG = False
+
+except Exception:
+    DEFAULT_DJANGO_DEBUG = False
+
+print("\n---> DJANGO VARIABLES")
+print(f"DEFAULT_TOKEN_EXPIRE_MIN: {DEFAULT_TOKEN_EXPIRE_MIN}")
+print(f"DEFAULT_TOKEN_REFRESH_DAYS: {DEFAULT_TOKEN_REFRESH_DAYS}")
+print(f"DEFAULT_DJANGO_DEBUG: {DEFAULT_DJANGO_DEBUG}")
+print("<---DJANGO VARIABLES\n")
+
+# Application definition
+INSTALLED_APPS = [
+    "django.contrib.admin",
+    "django.contrib.auth",
+    "django.contrib.contenttypes",
+    "django.contrib.sessions",
+    "django.contrib.messages",
+    "django.contrib.staticfiles",
+    ### ADDED
+    "rest_framework",
+    ### SWAGGER
+    "drf_yasg",
+    ### JWT TOKEN
+    "rest_framework_simplejwt",
+    ### SSL
+    "sslserver",
+    ### MY STUFF
+    "shared_models",
+    "api",
+    "api_auth",
+    "api_admin",
+]
+
+###
+### AUTH
+###
+REST_FRAMEWORK = {
+    'DEFAULT_PERMISSION_CLASSES': [
+        'rest_framework.permissions.IsAuthenticated',  # Require authentication for all endpoints
+    ],
+    'DEFAULT_AUTHENTICATION_CLASSES': (
+        'rest_framework.authentication.SessionAuthentication',
+        'rest_framework.authentication.BasicAuthentication',
+    ),
+}
+SESSION_ENGINE = "django.contrib.sessions.backends.db"
+LOGIN_REDIRECT_URL = '/swagger/'  # Redirect here after login
+LOGIN_URL = '/auth/login/'  # The URL to redirect to for login
+LOGOUT_REDIRECT_URL = '/auth/login/'  # Redirect here after logout
+###
+### TOKEN
+###
+SIMPLE_JWT = {
+    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=DEFAULT_TOKEN_EXPIRE_MIN),
+    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=DEFAULT_TOKEN_REFRESH_DAYS),
+    'SLIDING_TOKEN_LIFETIME': timedelta(days=30),
+    'SLIDING_TOKEN_REFRESH_LIFETIME_LATE_USER': timedelta(days=3),
+    'SLIDING_TOKEN_LIFETIME_LATE_USER': timedelta(days=30),
+}
+
+
+MIDDLEWARE = [
+    "django.middleware.security.SecurityMiddleware",
+    "django.contrib.sessions.middleware.SessionMiddleware",
+    "django.middleware.common.CommonMiddleware",
+    "django.middleware.csrf.CsrfViewMiddleware",
+    "django.contrib.auth.middleware.AuthenticationMiddleware",
+    "django.contrib.messages.middleware.MessageMiddleware",
+    "django.middleware.clickjacking.XFrameOptionsMiddleware",
+    ###
+    ### ADDED
+    ###
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.middleware.security.SecurityMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = "backend.urls"
+
+TEMPLATES = [
+    {
+        "BACKEND": "django.template.backends.django.DjangoTemplates",
+        "DIRS": [],
+        "APP_DIRS": True,
+        "OPTIONS": {
+            "context_processors": [
+                "django.template.context_processors.debug",
+                "django.template.context_processors.request",
+                "django.contrib.auth.context_processors.auth",
+                "django.contrib.messages.context_processors.messages",
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = "backend.wsgi.application"
+
+
+# Database
+# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
+
+DATABASES = {
+    "default": {
+        "ENGINE": "django.db.backends.sqlite3",
+        "NAME": BASE_DIR / "db.sqlite3",
+    }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
+    },
+    {
+        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
+    },
+    {
+        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
+    },
+    {
+        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/5.1/topics/i18n/
+
+LANGUAGE_CODE = "en-us"
+
+# TIME_ZONE = "UTC"
+TIME_ZONE = 'Europe/Berlin'
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/5.1/howto/static-files/
+
+STATIC_URL = "static/"
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
diff --git a/django/backend/urls.py b/django/backend/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..4b69704129762eafac55f79634a742456f7cbc58
--- /dev/null
+++ b/django/backend/urls.py
@@ -0,0 +1,55 @@
+"""
+URL configuration for backend project.
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/5.1/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+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 rest_framework import permissions
+from drf_yasg.views import get_schema_view
+from drf_yasg import openapi
+from django.contrib import admin
+from django.urls import path, include
+
+
+schema_view = get_schema_view(
+    openapi.Info(
+        title="c3buttons",
+        default_version='1.0.0',
+        description="Swagger Documentation for c3buttons",
+        # terms_of_service="https://link.to.something",
+        contact=openapi.Contact(name="fejao", email="dont@bug.me"),
+        license=openapi.License(name="MIT"),
+    ),
+    ### AUTH
+    public=False,
+    permission_classes=(permissions.IsAuthenticated,),
+
+)
+
+
+urlpatterns = [
+    path("admin/", admin.site.urls),
+    ###
+    ### SWAGGER
+    ###
+    path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
+    path('swagger.json/', schema_view.without_ui(cache_timeout=0), name='schema-json'),
+    ###
+    ### APPS
+    ###
+    path('auth/', include('api_auth.urls')),
+    # path("api/box/", include("api.urls")),
+    path("api/", include("api.urls")),
+    path("api-admin/", include("api_admin.urls")),
+]
diff --git a/django/backend/wsgi.py b/django/backend/wsgi.py
new file mode 100644
index 0000000000000000000000000000000000000000..ae9503c61e3d7dadd1a1a77229acfb6c9f4db746
--- /dev/null
+++ b/django/backend/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for backend project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
+
+application = get_wsgi_application()
diff --git a/django/manage.py b/django/manage.py
new file mode 100755
index 0000000000000000000000000000000000000000..1917e46e5a9417d34d1131e11fcba9665feb978e
--- /dev/null
+++ b/django/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+    """Run administrative tasks."""
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings")
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError as exc:
+        raise ImportError(
+            "Couldn't import Django. Are you sure it's installed and "
+            "available on your PYTHONPATH environment variable? Did you "
+            "forget to activate a virtual environment?"
+        ) from exc
+    execute_from_command_line(sys.argv)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/django/requirements.txt b/django/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..54dae6864951a8f32dedb9cc53afe27f68471fbc
--- /dev/null
+++ b/django/requirements.txt
@@ -0,0 +1,10 @@
+dotenv
+### DJANGO
+django
+djangorestframework
+### SWAGGER
+drf-yasg
+### TOKEN
+djangorestframework-simplejwt
+### SSL
+django-sslserver
diff --git a/django/shared_models/__init__.py b/django/shared_models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/django/shared_models/apps.py b/django/shared_models/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..6668dfbfcd134da33dfefcb3ff53268296f68fdd
--- /dev/null
+++ b/django/shared_models/apps.py
@@ -0,0 +1,12 @@
+"""
+    Default setted file from django for an added app.
+"""
+
+from django.apps import AppConfig
+
+
+class SharedModelsConfig(AppConfig):
+    """Default setted SharedModelsConfig class for the app.
+    """
+    default_auto_field = "django.db.models.BigAutoField"
+    name = "shared_models"
diff --git a/django/shared_models/migrations/0001_initial.py b/django/shared_models/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..57ae4cea77ddbdda0ea267aee43b421b1541d0f7
--- /dev/null
+++ b/django/shared_models/migrations/0001_initial.py
@@ -0,0 +1,38 @@
+# Generated by Django 5.1.6 on 2025-03-03 18:22
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ButtonBox',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=40, unique=True)),
+                ('pin_button', models.PositiveIntegerField(unique=True)),
+                ('pin_led', models.PositiveIntegerField(unique=True)),
+            ],
+            options={
+                'db_table': 'button_box',
+            },
+        ),
+        migrations.CreateModel(
+            name='ButtonBoxUse',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('date', models.DateTimeField(auto_now_add=True)),
+                ('box_used', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='shared_models.buttonbox')),
+            ],
+            options={
+                'db_table': 'button_box_use',
+            },
+        ),
+    ]
diff --git a/django/shared_models/migrations/__init__.py b/django/shared_models/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/django/shared_models/models.py b/django/shared_models/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..f7010ef221c05783e949bf0b69139d7dd88f210c
--- /dev/null
+++ b/django/shared_models/models.py
@@ -0,0 +1,49 @@
+"""
+    Serializers for the models shared among this django.
+"""
+
+from django.db import models
+
+
+class ButtonBox(models.Model):
+    """The model for storing the information about the button box.
+    """
+    name = models.CharField(max_length=40, unique=True)
+    # pin_number = models.PositiveIntegerField(unique=True)
+    pin_button = models.PositiveIntegerField(unique=True)
+    pin_led = models.PositiveIntegerField(unique=True)
+
+    class Meta:
+        """ Meta class for the Button Box model.
+        Used for setting the name ot the table at the DB.
+        """
+        db_table = "button_box"
+
+    def __str__(self):
+        """Override from the default __str__ method for returning the name of the box instead of it's ID.
+        """
+        return str(self.name)
+
+
+class ButtonBoxUse(models.Model):
+    """The model for storing the information about the button box uses.
+    """
+
+    box_used = models.ForeignKey(
+        ButtonBox,
+        on_delete=models.CASCADE,
+    )
+    date = models.DateTimeField(auto_now_add=True, blank=True)
+
+    class Meta:
+        """ Meta class for the Button Box Use model.
+        Used for setting the name ot the table at the DB.
+        """
+        db_table = "button_box_use"
+
+    @property
+    def box_name(self):
+        """Property method for fetching the name of the box for the box used.
+        """
+        box_obj = ButtonBox.objects.get(name=self.box_used)
+        return box_obj.name
diff --git a/django/shared_models/serializers.py b/django/shared_models/serializers.py
new file mode 100644
index 0000000000000000000000000000000000000000..4bc1c3b968538ac05761f1d80fca63a5a168aa53
--- /dev/null
+++ b/django/shared_models/serializers.py
@@ -0,0 +1,41 @@
+"""
+    Serializer used for the used shared models among the apps.
+"""
+
+from rest_framework import serializers
+from .models import ButtonBox, ButtonBoxUse
+
+
+class ButtonBoxSerializer(serializers.ModelSerializer):
+    """The serializer for the information about the button box.
+    """
+
+    class Meta:
+        """ Meta class for the ButtonBoxSerializer.
+        Used for returning only the information needed for the ButtonBox model.
+        """
+        model = ButtonBox
+        fields = [
+            # "id",
+            "name",
+            # "pin_number",
+            "pin_button",
+            "pin_led",
+        ]
+
+
+class ButtonBoxUseSerializer(serializers.ModelSerializer):
+    """The serializer for the information about the button box uses.
+    """
+
+    class Meta:
+        """ Meta class for the ButtonBoxSerializer.
+        Used for returning only the information needed for the ButtonBoxUse model.
+        """
+        model = ButtonBoxUse
+        fields = [
+            # "id",
+            "box_used",
+            "box_name",
+            "date",
+        ]