diff --git a/.env_example b/.env_example
new file mode 100644
index 0000000000000000000000000000000000000000..5aba0d14603ad3939f8bd439de4b49f57e29c016
--- /dev/null
+++ b/.env_example
@@ -0,0 +1,13 @@
+DJANGO_APP_STAGE="dev"
+# Only used in dev mode, change to "postgresql" if you want to use PostgreSQL in dev
+DJANGO_DEV_STORE_METHOD="sqllite"
+DJANGO_DB_HOST="localhost"
+DJANGO_DB_NAME="note_db"
+DJANGO_DB_USER="note"
+DJANGO_DB_PASSWORD="CHANGE_ME"
+DJANGO_DB_PORT=""
+DJANGO_SECRET_KEY="CHANGE_ME"
+DJANGO_SETTINGS_MODULE="note_kfet.settings"
+DOMAIN="localhost"
+CONTACT_EMAIL="tresorerie.bde@localhost"
+NOTE_URL="localhost"
diff --git a/Dockerfile b/Dockerfile
index a2f45b0058c0cb4dad27d946b7c1f146b21104fa..d42bdd1f479c7155f33160d75271f54c1bd5ee6c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -9,13 +9,13 @@ RUN apt update && \
     apt install -y gettext nginx uwsgi uwsgi-plugin-python3 && \
     rm -rf /var/lib/apt/lists/*
 
-COPY requirements.txt /code/
+COPY . /code/
+
+# Comment what is not needed
 RUN pip install -r requirements/base.txt
 RUN pip install -r requirements/api.txt
 RUN pip install -r requirements/cas.txt
 RUN pip install -r requirements/production.txt
 
-COPY . /code/
-
 ENTRYPOINT ["/code/entrypoint.sh"]
 EXPOSE 8000
diff --git a/README.md b/README.md
index 14ec5f4243be000161ebf38947f0c2c2f5f8551d..91f2f17d48de7d9e4c1077fca7826318745ec7a4 100644
--- a/README.md
+++ b/README.md
@@ -40,14 +40,13 @@ On supposera pour la suite que vous utiliser debian/ubuntu sur un serveur tout n
 
         $ cp nginx_note.conf_example nginx_note.conf
 
-***Modifier le fichier pour être en accord avec le reste de votre config***
+    ***Modifier le fichier pour être en accord avec le reste de votre config***
 
     On utilise uwsgi et Nginx pour gérer le coté serveur :
 
-        $ sudo ln -sf /var/www/note_kfet/nginx_note.conf /etc/nginx/sites-enabled/
+       $ sudo ln -sf /var/www/note_kfet/nginx_note.conf /etc/nginx/sites-enabled/
 
-
-    Si l'on a un emperor (plusieurs instance uwsgi):
+   Si l'on a un emperor (plusieurs instance uwsgi):
 
         $ sudo ln -sf /var/www/note_kfet/uwsgi_note.ini /etc/uwsgi/sites/
 
@@ -85,7 +84,7 @@ On supposera pour la suite que vous utiliser debian/ubuntu sur un serveur tout n
         postgres=# CREATE DATABASE note_db OWNER note;
         CREATE DATABASE
 
-    Si tout va bien:
+    Si tout va bien :
         
         postgres=#\list
         List of databases
@@ -96,22 +95,29 @@ On supposera pour la suite que vous utiliser debian/ubuntu sur un serveur tout n
          template0 | postgres | UTF8     | fr_FR.UTF-8 | fr_FR.UTF-8 | =c/postgres+postgres=CTc/postgres
          template1 | postgres | UTF8     | fr_FR.UTF-8 | fr_FR.UTF-8 | =c/postgres  +postgres=CTc/postgres
         (4 rows)
-
-    Dans un fichier `.env` à la racine du projet on renseigne des secrets:
     
-        DJANGO_APP_STAGE='prod'
-        DJANGO_DB_PASSWORD='le_mot_de_passe_de_la_bdd'
-        DJANGO_SECRET_KEY='une_secret_key_longue_et_compliquee'
-        ALLOWED_HOSTS='le_ndd_de_votre_instance'
-    
-
 6. Variable d'environnement et Migrations
         
-
-Ensuite on (re)bascule dans l'environement virtuel et on lance les migrations
+    On copie le fichier `.env_example` vers le fichier `.env` à la racine du projet 
+    et on renseigne des secrets et des paramètres :
+    
+        DJANGO_APP_STAGE="dev"
+        DJANGO_DEV_STORE_METHOD="sqllite"
+        DJANGO_DB_HOST="localhost"
+        DJANGO_DB_NAME="note_db"
+        DJANGO_DB_USER="note"
+        DJANGO_DB_PASSWORD="CHANGE_ME"
+        DJANGO_DB_PORT=""
+        DJANGO_SECRET_KEY="CHANGE_ME"
+        DJANGO_SETTINGS_MODULE="note_kfet.settings"
+        DOMAIN="localhost"
+        CONTACT_EMAIL="tresorerie.bde@localhost"
+        NOTE_URL="localhost"
+
+    Ensuite on (re)bascule dans l'environement virtuel et on lance les migrations
 
         $ source /env/bin/activate
-        (env)$ ./manage.py check # pas de bétise qui traine
+        (env)$ ./manage.py check # pas de bêtise qui traine
         (env)$ ./manage.py makemigrations
         (env)$ ./manage.py migrate
 
@@ -126,17 +132,21 @@ Il est possible de travailler sur une instance Docker.
     
         $ git clone git@gitlab.crans.org:bde/nk20.git
 
-2. Dans le fichier `docker_compose.yml`, qu'on suppose déjà configuré,
+2. Copiez le fichier `.env_example` à la racine du projet vers le fichier `.env`,
+et  mettez à jour vos variables d'environnement
+
+3. Dans le fichier `docker_compose.yml`, qu'on suppose déjà configuré,
    ajouter les lignes suivantes, en les adaptant à la configuration voulue :
 
         nk20:
           build: /chemin/vers/nk20
           volumes:
             - /chemin/vers/nk20:/code/
+          env_file: /chemin/vers/nk20/.env
           restart: always
           labels:
-            - traefik.domain=ndd.exemple.com
-            - traefik.frontend.rule=Host:ndd.exemple.com
+            - traefik.domain=ndd.example.com
+            - traefik.frontend.rule=Host:ndd.example.com
             - traefik.port=8000
 
 3. Enjoy :
@@ -159,17 +169,20 @@ un serveur de développement par exemple sur son ordinateur.
         $ source venv/bin/activate
         (env)$ pip install -r requirements.txt
 
-3. Migrations et chargement des données initiales :
+3. Copier le fichier `.env_example` vers `.env` à la racine du projet et mettre à jour
+ce qu'il faut
+
+4. Migrations et chargement des données initiales :
 
         (env)$ ./manage.py makemigrations
         (env)$ ./manage.py migrate
         (env)$ ./manage.py loaddata initial
 
-4. Créer un super-utilisateur :
+5. Créer un super-utilisateur :
 
         (env)$ ./manage.py createsuperuser
 
-5. Enjoy :
+6. Enjoy :
 
         (env)$ ./manage.py runserver 0.0.0.0:8000
 
@@ -184,4 +197,4 @@ Il est disponible [ici](https://wiki.crans.org/NoteKfet/NoteKfet2018/CdC).
 ## Documentation
 
 La documentation est générée par django et son module admindocs.
-**Commenter votre code !**
+**Commentez votre code !**
diff --git a/apps/activity/api/views.py b/apps/activity/api/views.py
index 6a6c024ef0d4ef89dbff763dd0a4ce529699c6b8..4ee2194d06c38cad2726feb8536c149248aa336b 100644
--- a/apps/activity/api/views.py
+++ b/apps/activity/api/views.py
@@ -1,7 +1,8 @@
 # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
-
+from django_filters.rest_framework import DjangoFilterBackend
 from rest_framework import viewsets
+from rest_framework.filters import SearchFilter
 
 from .serializers import ActivityTypeSerializer, ActivitySerializer, GuestSerializer
 from ..models import ActivityType, Activity, Guest
@@ -15,6 +16,8 @@ class ActivityTypeViewSet(viewsets.ModelViewSet):
     """
     queryset = ActivityType.objects.all()
     serializer_class = ActivityTypeSerializer
+    filter_backends = [DjangoFilterBackend]
+    filterset_fields = ['name', 'can_invite', ]
 
 
 class ActivityViewSet(viewsets.ModelViewSet):
@@ -25,6 +28,8 @@ class ActivityViewSet(viewsets.ModelViewSet):
     """
     queryset = Activity.objects.all()
     serializer_class = ActivitySerializer
+    filter_backends = [DjangoFilterBackend]
+    filterset_fields = ['name', 'description', 'activity_type', ]
 
 
 class GuestViewSet(viewsets.ModelViewSet):
@@ -35,3 +40,5 @@ class GuestViewSet(viewsets.ModelViewSet):
     """
     queryset = Guest.objects.all()
     serializer_class = GuestSerializer
+    filter_backends = [SearchFilter]
+    search_fields = ['$name', ]
diff --git a/apps/api/urls.py b/apps/api/urls.py
index c1b6bf48baa5970e7b16022552f38f5be15ee5c9..95ed5f99e9005850fed2822d3ef081bf5ec55b85 100644
--- a/apps/api/urls.py
+++ b/apps/api/urls.py
@@ -3,10 +3,14 @@
 
 from django.conf.urls import url, include
 from django.contrib.auth.models import User
+from django.contrib.contenttypes.models import ContentType
+from django_filters.rest_framework import DjangoFilterBackend
 from rest_framework import routers, serializers, viewsets
+from rest_framework.filters import SearchFilter
 from activity.api.urls import register_activity_urls
 from member.api.urls import register_members_urls
 from note.api.urls import register_note_urls
+from logs.api.urls import register_logs_urls
 
 
 class UserSerializer(serializers.ModelSerializer):
@@ -24,6 +28,17 @@ class UserSerializer(serializers.ModelSerializer):
         )
 
 
+class ContentTypeSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Users.
+    The djangorestframework plugin will analyse the model `User` and parse all fields in the API.
+    """
+
+    class Meta:
+        model = ContentType
+        fields = '__all__'
+
+
 class UserViewSet(viewsets.ModelViewSet):
     """
     REST API View set.
@@ -32,15 +47,30 @@ class UserViewSet(viewsets.ModelViewSet):
     """
     queryset = User.objects.all()
     serializer_class = UserSerializer
+    filter_backends = [DjangoFilterBackend, SearchFilter]
+    filterset_fields = ['id', 'username', 'first_name', 'last_name', 'email', 'is_superuser', 'is_staff', 'is_active', ]
+    search_fields = ['$username', '$first_name', '$last_name', ]
+
+
+class ContentTypeViewSet(viewsets.ReadOnlyModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `User` objects, serialize it to JSON with the given serializer,
+    then render it on /api/users/
+    """
+    queryset = ContentType.objects.all()
+    serializer_class = ContentTypeSerializer
 
 
 # Routers provide an easy way of automatically determining the URL conf.
 # Register each app API router and user viewset
 router = routers.DefaultRouter()
+router.register('models', ContentTypeViewSet)
 router.register('user', UserViewSet)
 register_members_urls(router, 'members')
 register_activity_urls(router, 'activity')
 register_note_urls(router, 'note')
+register_logs_urls(router, 'logs')
 
 app_name = 'api'
 
diff --git a/apps/logs/api/__init__.py b/apps/logs/api/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/apps/logs/api/serializers.py b/apps/logs/api/serializers.py
new file mode 100644
index 0000000000000000000000000000000000000000..c76e3a5d8d43c0f52ef17f14971d88f864cb6580
--- /dev/null
+++ b/apps/logs/api/serializers.py
@@ -0,0 +1,19 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from rest_framework import serializers
+
+from ..models import Changelog
+
+
+class ChangelogSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Changelog types.
+    The djangorestframework plugin will analyse the model `Changelog` and parse all fields in the API.
+    """
+
+    class Meta:
+        model = Changelog
+        fields = '__all__'
+        # noinspection PyProtectedMember
+        read_only_fields = [f.name for f in model._meta.get_fields()]  # Changelogs are read-only protected
diff --git a/apps/logs/api/urls.py b/apps/logs/api/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..9a0ceaa8cec01b81f5bf5646bec374ab16199a42
--- /dev/null
+++ b/apps/logs/api/urls.py
@@ -0,0 +1,11 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from .views import ChangelogViewSet
+
+
+def register_logs_urls(router, path):
+    """
+    Configure router for Activity REST API.
+    """
+    router.register(path, ChangelogViewSet)
diff --git a/apps/logs/api/views.py b/apps/logs/api/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c47b7a2a5daf50ef5d56d1a487d1b9b4050a98c
--- /dev/null
+++ b/apps/logs/api/views.py
@@ -0,0 +1,23 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from django_filters.rest_framework import DjangoFilterBackend
+from rest_framework import viewsets
+from rest_framework.filters import OrderingFilter
+
+from .serializers import ChangelogSerializer
+from ..models import Changelog
+
+
+class ChangelogViewSet(viewsets.ReadOnlyModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Changelog` objects, serialize it to JSON with the given serializer,
+    then render it on /api/logs/
+    """
+    queryset = Changelog.objects.all()
+    serializer_class = ChangelogSerializer
+    filter_backends = [DjangoFilterBackend, OrderingFilter]
+    filterset_fields = ['model', 'action', "instance_pk", 'user', 'ip', ]
+    ordering_fields = ['timestamp', ]
+    ordering = ['-timestamp', ]
diff --git a/apps/logs/apps.py b/apps/logs/apps.py
index f48820c7b91f2e9818aa179ce94ff2960d07884e..239f86cf45cd58326ae68e2349b0c1e6421dd307 100644
--- a/apps/logs/apps.py
+++ b/apps/logs/apps.py
@@ -2,6 +2,7 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.apps import AppConfig
+from django.db.models.signals import pre_save, post_save, post_delete
 from django.utils.translation import gettext_lazy as _
 
 
@@ -11,4 +12,7 @@ class LogsConfig(AppConfig):
 
     def ready(self):
         # noinspection PyUnresolvedReferences
-        import logs.signals
+        from . import signals
+        pre_save.connect(signals.pre_save_object)
+        post_save.connect(signals.save_object)
+        post_delete.connect(signals.delete_object)
diff --git a/apps/logs/middlewares.py b/apps/logs/middlewares.py
new file mode 100644
index 0000000000000000000000000000000000000000..77f749b9da0663a4a3fd4e1b17aa8c8967fc5372
--- /dev/null
+++ b/apps/logs/middlewares.py
@@ -0,0 +1,55 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from django.conf import settings
+from django.contrib.auth.models import AnonymousUser
+
+from threading import local
+
+
+USER_ATTR_NAME = getattr(settings, 'LOCAL_USER_ATTR_NAME', '_current_user')
+IP_ATTR_NAME = getattr(settings, 'LOCAL_IP_ATTR_NAME', '_current_ip')
+
+_thread_locals = local()
+
+
+def _set_current_user_and_ip(user=None, ip=None):
+    setattr(_thread_locals, USER_ATTR_NAME, user)
+    setattr(_thread_locals, IP_ATTR_NAME, ip)
+
+
+def get_current_user():
+    return getattr(_thread_locals, USER_ATTR_NAME, None)
+
+
+def get_current_ip():
+    return getattr(_thread_locals, IP_ATTR_NAME, None)
+
+
+def get_current_authenticated_user():
+    current_user = get_current_user()
+    if isinstance(current_user, AnonymousUser):
+        return None
+    return current_user
+
+
+class LogsMiddleware(object):
+    """
+    This middleware get the current user with his or her IP address on each request.
+    """
+
+    def __init__(self, get_response):
+        self.get_response = get_response
+
+    def __call__(self, request):
+        user = request.user
+        if 'HTTP_X_FORWARDED_FOR' in request.META:
+            ip = request.META.get('HTTP_X_FORWARDED_FOR')
+        else:
+            ip = request.META.get('REMOTE_ADDR')
+
+        _set_current_user_and_ip(user, ip)
+        response = self.get_response(request)
+        _set_current_user_and_ip(None, None)
+
+        return response
diff --git a/apps/logs/models.py b/apps/logs/models.py
index 9ab3cf6a3a347081c66ea441cd8f56704e43de9c..10e2651f2f8475c4241c05a37f9c56b37c8d5bb5 100644
--- a/apps/logs/models.py
+++ b/apps/logs/models.py
@@ -56,6 +56,12 @@ class Changelog(models.Model):
         max_length=16,
         null=False,
         blank=False,
+        choices=[
+            ('create', _('create')),
+            ('edit', _('edit')),
+            ('delete', _('delete')),
+        ],
+        default='edit',
         verbose_name=_('action'),
     )
 
diff --git a/apps/logs/signals.py b/apps/logs/signals.py
index 415e7c1c63ceec002c9b478bc81f224602e0e73f..fb17157a9fc14f8b22dc99bab586b95b60e6f834 100644
--- a/apps/logs/signals.py
+++ b/apps/logs/signals.py
@@ -1,67 +1,40 @@
 # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
-import inspect
-
 from django.contrib.contenttypes.models import ContentType
-from django.core import serializers
-from django.db.models.signals import pre_save, post_save, post_delete
-from django.dispatch import receiver
-
-from .models import Changelog
-
-
-def get_request_in_signal(sender):
-    req = None
-    for entry in reversed(inspect.stack()):
-        try:
-            req = entry[0].f_locals['request']
-            # Check if there is a user
-            # noinspection PyStatementEffect
-            req.user
-            break
-        except:
-            pass
-
-    if not req:
-        print("WARNING: Attempt to save " + str(sender) + " with no user")
+from rest_framework.renderers import JSONRenderer
+from rest_framework.serializers import ModelSerializer
 
-    return req
+import getpass
 
+from note.models import NoteUser, Alias
 
-def get_user_and_ip(sender):
-    req = get_request_in_signal(sender)
-    try:
-        user = req.user
-        if 'HTTP_X_FORWARDED_FOR' in req.META:
-            ip = req.META.get('HTTP_X_FORWARDED_FOR')
-        else:
-            ip = req.META.get('REMOTE_ADDR')
-    except:
-        user = None
-        ip = None
-    return user, ip
+from .middlewares import get_current_authenticated_user, get_current_ip
+from .models import Changelog
 
 
+# Ces modèles ne nécessitent pas de logs
 EXCLUDED = [
     'admin.logentry',
     'authtoken.token',
+    'cas_server.proxygrantingticket',
+    'cas_server.proxyticket',
+    'cas_server.serviceticket',
     'cas_server.user',
     'cas_server.userattributes',
     'contenttypes.contenttype',
-    'logs.changelog',
+    'logs.changelog',  # Never remove this line
     'migrations.migration',
-    'note.noteuser',
-    'note.noteclub',
-    'note.notespecial',
+    'note.note'  # We only store the subclasses
+    'note.transaction',
     'sessions.session',
-    'reversion.revision',
-    'reversion.version',
 ]
 
 
-@receiver(pre_save)
 def pre_save_object(sender, instance, **kwargs):
+    """
+    Before a model get saved, we get the previous instance that is currently in the database
+    """
     qs = sender.objects.filter(pk=instance.pk).all()
     if qs.exists():
         instance._previous = qs.get()
@@ -69,30 +42,51 @@ def pre_save_object(sender, instance, **kwargs):
         instance._previous = None
 
 
-@receiver(post_save)
 def save_object(sender, instance, **kwargs):
+    """
+    Each time a model is saved, an entry in the table `Changelog` is added in the database
+    in order to store each modification made
+    """
     # noinspection PyProtectedMember
     if instance._meta.label_lower in EXCLUDED:
         return
 
+    # noinspection PyProtectedMember
     previous = instance._previous
 
-    user, ip = get_user_and_ip(sender)
-
-    from django.contrib.auth.models import AnonymousUser
-    if isinstance(user, AnonymousUser):
-        user = None
+    # Si un utilisateur est connecté, on récupère l'utilisateur courant ainsi que son adresse IP
+    user, ip = get_current_authenticated_user(), get_current_ip()
+
+    if user is None:
+        # Si la modification n'a pas été faite via le client Web, on suppose que c'est du à `manage.py`
+        # On récupère alors l'utilisateur·trice connecté·e à la VM, et on récupère la note associée
+        # IMPORTANT : l'utilisateur dans la VM doit être un des alias note du respo info
+        ip = "127.0.0.1"
+        username = Alias.normalize(getpass.getuser())
+        note = NoteUser.objects.filter(alias__normalized_name=username)
+        # if not note.exists():
+        #     print("WARNING: A model attempted to be saved in the DB, but the actor is unknown: " + username)
+        # else:
+        if note.exists():
+            user = note.get().user
 
+    # noinspection PyProtectedMember
     if user is not None and instance._meta.label_lower == "auth.user" and previous:
-        # Don't save last login modifications
+        # On n'enregistre pas les connexions
         if instance.last_login != previous.last_login:
             return
 
-    previous_json = serializers.serialize('json', [previous, ])[1:-1] if previous else None
-    instance_json = serializers.serialize('json', [instance, ])[1:-1]
+    # On crée notre propre sérialiseur JSON pour pouvoir sauvegarder les modèles
+    class CustomSerializer(ModelSerializer):
+        class Meta:
+            model = instance.__class__
+            fields = '__all__'
+
+    previous_json = JSONRenderer().render(CustomSerializer(previous).data).decode("UTF-8") if previous else None
+    instance_json = JSONRenderer().render(CustomSerializer(instance).data).decode("UTF-8")
 
     if previous_json == instance_json:
-        # No modification
+        # Pas de log s'il n'y a pas de modification
         return
 
     Changelog.objects.create(user=user,
@@ -105,15 +99,38 @@ def save_object(sender, instance, **kwargs):
                              ).save()
 
 
-@receiver(post_delete)
 def delete_object(sender, instance, **kwargs):
+    """
+    Each time a model is deleted, an entry in the table `Changelog` is added in the database
+    """
     # noinspection PyProtectedMember
     if instance._meta.label_lower in EXCLUDED:
         return
 
-    user, ip = get_user_and_ip(sender)
+    # Si un utilisateur est connecté, on récupère l'utilisateur courant ainsi que son adresse IP
+    user, ip = get_current_authenticated_user(), get_current_ip()
+
+    if user is None:
+        # Si la modification n'a pas été faite via le client Web, on suppose que c'est du à `manage.py`
+        # On récupère alors l'utilisateur·trice connecté·e à la VM, et on récupère la note associée
+        # IMPORTANT : l'utilisateur dans la VM doit être un des alias note du respo info
+        ip = "127.0.0.1"
+        username = Alias.normalize(getpass.getuser())
+        note = NoteUser.objects.filter(alias__normalized_name=username)
+        # if not note.exists():
+        #     print("WARNING: A model attempted to be saved in the DB, but the actor is unknown: " + username)
+        # else:
+        if note.exists():
+            user = note.get().user
+
+    # On crée notre propre sérialiseur JSON pour pouvoir sauvegarder les modèles
+    class CustomSerializer(ModelSerializer):
+        class Meta:
+            model = instance.__class__
+            fields = '__all__'
+
+    instance_json = JSONRenderer().render(CustomSerializer(instance).data).decode("UTF-8")
 
-    instance_json = serializers.serialize('json', [instance, ])[1:-1]
     Changelog.objects.create(user=user,
                              ip=ip,
                              model=ContentType.objects.get_for_model(instance),
diff --git a/apps/logs/urls.py b/apps/logs/urls.py
deleted file mode 100644
index 6d76674c0b0835042b4c6ae15d843d29dd070612..0000000000000000000000000000000000000000
--- a/apps/logs/urls.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
-# SPDX-License-Identifier: GPL-3.0-or-later
-
-app_name = 'logs'
-
-# TODO User interface
-urlpatterns = [
-]
diff --git a/apps/member/api/views.py b/apps/member/api/views.py
index 7e7dcd1d41bed62d91b82e625f750a59845af839..c85df90330ae00463306d30b6bec3da8c22abc97 100644
--- a/apps/member/api/views.py
+++ b/apps/member/api/views.py
@@ -2,6 +2,7 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from rest_framework import viewsets
+from rest_framework.filters import SearchFilter
 
 from .serializers import ProfileSerializer, ClubSerializer, RoleSerializer, MembershipSerializer
 from ..models import Profile, Club, Role, Membership
@@ -25,6 +26,8 @@ class ClubViewSet(viewsets.ModelViewSet):
     """
     queryset = Club.objects.all()
     serializer_class = ClubSerializer
+    filter_backends = [SearchFilter]
+    search_fields = ['$name', ]
 
 
 class RoleViewSet(viewsets.ModelViewSet):
@@ -35,6 +38,8 @@ class RoleViewSet(viewsets.ModelViewSet):
     """
     queryset = Role.objects.all()
     serializer_class = RoleSerializer
+    filter_backends = [SearchFilter]
+    search_fields = ['$name', ]
 
 
 class MembershipViewSet(viewsets.ModelViewSet):
diff --git a/apps/member/models.py b/apps/member/models.py
index 5cdc4c77e6d151f34b94023f7803b5ee3955af5a..b6d17a089f7c2c74ac80ec1f820dbba29f0b8ff7 100644
--- a/apps/member/models.py
+++ b/apps/member/models.py
@@ -46,7 +46,7 @@ class Profile(models.Model):
     class Meta:
         verbose_name = _('user profile')
         verbose_name_plural = _('user profile')
-        indexes = [ models.Index(fields=['user']) ]
+        indexes = [models.Index(fields=['user'])]
 
     def get_absolute_url(self):
         return reverse('user_detail', args=(self.pk,))
@@ -153,7 +153,7 @@ class Membership(models.Model):
     class Meta:
         verbose_name = _('membership')
         verbose_name_plural = _('memberships')
-        indexes = [ models.Index(fields=['user']) ]
+        indexes = [models.Index(fields=['user'])]
 
 # @receiver(post_save, sender=settings.AUTH_USER_MODEL)
 # def save_user_profile(instance, created, **_kwargs):
diff --git a/apps/member/views.py b/apps/member/views.py
index 21c8de5f861144eb30169b6c8aeb15586c699ad9..82c15b99fd787a49adbed554999a36beb263e7a0 100644
--- a/apps/member/views.py
+++ b/apps/member/views.py
@@ -300,7 +300,7 @@ class UserAutocomplete(autocomplete.Select2QuerySetView):
         qs = User.objects.all()
 
         if self.q:
-            qs = qs.filter(username__regex=self.q)
+            qs = qs.filter(username__regex="^" + self.q)
 
         return qs
 
diff --git a/apps/note/api/serializers.py b/apps/note/api/serializers.py
index 1696bfeedbe0b2dd698191bbe1bc613733e2606d..73beead1aa374327e1449e1e6905c293702551ac 100644
--- a/apps/note/api/serializers.py
+++ b/apps/note/api/serializers.py
@@ -5,7 +5,8 @@ from rest_framework import serializers
 from rest_polymorphic.serializers import PolymorphicSerializer
 
 from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
-from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction
+from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction, TemplateCategory, \
+    TemplateTransaction
 
 
 class NoteSerializer(serializers.ModelSerializer):
@@ -78,6 +79,17 @@ class NotePolymorphicSerializer(PolymorphicSerializer):
     }
 
 
+class TemplateCategorySerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Transaction templates.
+    The djangorestframework plugin will analyse the model `TemplateCategory` and parse all fields in the API.
+    """
+
+    class Meta:
+        model = TemplateCategory
+        fields = '__all__'
+
+
 class TransactionTemplateSerializer(serializers.ModelSerializer):
     """
     REST API Serializer for Transaction templates.
@@ -100,6 +112,17 @@ class TransactionSerializer(serializers.ModelSerializer):
         fields = '__all__'
 
 
+class TemplateTransactionSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Transactions.
+    The djangorestframework plugin will analyse the model `TemplateTransaction` and parse all fields in the API.
+    """
+
+    class Meta:
+        model = TemplateTransaction
+        fields = '__all__'
+
+
 class MembershipTransactionSerializer(serializers.ModelSerializer):
     """
     REST API Serializer for Membership transactions.
@@ -109,3 +132,11 @@ class MembershipTransactionSerializer(serializers.ModelSerializer):
     class Meta:
         model = MembershipTransaction
         fields = '__all__'
+
+
+class TransactionPolymorphicSerializer(PolymorphicSerializer):
+    model_serializer_mapping = {
+        Transaction: TransactionSerializer,
+        TemplateTransaction: TemplateTransactionSerializer,
+        MembershipTransaction: MembershipTransactionSerializer,
+    }
diff --git a/apps/note/api/urls.py b/apps/note/api/urls.py
index 54218796211fb21173c9501b38f5cacff85f65dd..796a397f746aefd02c2e97b9aaf73bb25454f65a 100644
--- a/apps/note/api/urls.py
+++ b/apps/note/api/urls.py
@@ -2,7 +2,7 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from .views import NotePolymorphicViewSet, AliasViewSet, \
-    TransactionViewSet, TransactionTemplateViewSet, MembershipTransactionViewSet
+    TemplateCategoryViewSet, TransactionViewSet, TransactionTemplateViewSet
 
 
 def register_note_urls(router, path):
@@ -12,6 +12,6 @@ def register_note_urls(router, path):
     router.register(path + '/note', NotePolymorphicViewSet)
     router.register(path + '/alias', AliasViewSet)
 
+    router.register(path + '/transaction/category', TemplateCategoryViewSet)
     router.register(path + '/transaction/transaction', TransactionViewSet)
     router.register(path + '/transaction/template', TransactionTemplateViewSet)
-    router.register(path + '/transaction/membership', MembershipTransactionViewSet)
diff --git a/apps/note/api/views.py b/apps/note/api/views.py
index cf0136f216ab9cb0b6b9ced0cb5d18a4a6f053cb..14f640032f95fca049a4424502755173c8120182 100644
--- a/apps/note/api/views.py
+++ b/apps/note/api/views.py
@@ -2,13 +2,15 @@
 # SPDX-License-Identifier: GPL-3.0-or-later
 
 from django.db.models import Q
+from django_filters.rest_framework import DjangoFilterBackend
 from rest_framework import viewsets
+from rest_framework.filters import SearchFilter
 
 from .serializers import NoteSerializer, NotePolymorphicSerializer, NoteClubSerializer, NoteSpecialSerializer, \
     NoteUserSerializer, AliasSerializer, \
-    TransactionTemplateSerializer, TransactionSerializer, MembershipTransactionSerializer
+    TemplateCategorySerializer, TransactionTemplateSerializer, TransactionPolymorphicSerializer
 from ..models.notes import Note, NoteClub, NoteSpecial, NoteUser, Alias
-from ..models.transactions import TransactionTemplate, Transaction, MembershipTransaction
+from ..models.transactions import TransactionTemplate, Transaction, TemplateCategory
 
 
 class NoteViewSet(viewsets.ModelViewSet):
@@ -69,8 +71,8 @@ class NotePolymorphicViewSet(viewsets.ModelViewSet):
 
         alias = self.request.query_params.get("alias", ".*")
         queryset = queryset.filter(
-            Q(alias__name__regex=alias)
-            | Q(alias__normalized_name__regex=alias.lower()))
+            Q(alias__name__regex="^" + alias)
+            | Q(alias__normalized_name__regex="^" + alias.lower()))
 
         note_type = self.request.query_params.get("type", None)
         if note_type:
@@ -107,7 +109,7 @@ class AliasViewSet(viewsets.ModelViewSet):
 
         alias = self.request.query_params.get("alias", ".*")
         queryset = queryset.filter(
-            Q(name__regex=alias) | Q(normalized_name__regex=alias.lower()))
+            Q(name__regex="^" + alias) | Q(normalized_name__regex="^" + alias.lower()))
 
         note_id = self.request.query_params.get("note", None)
         if note_id:
@@ -131,6 +133,18 @@ class AliasViewSet(viewsets.ModelViewSet):
         return queryset
 
 
+class TemplateCategoryViewSet(viewsets.ModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `TemplateCategory` objects, serialize it to JSON with the given serializer,
+    then render it on /api/note/transaction/category/
+    """
+    queryset = TemplateCategory.objects.all()
+    serializer_class = TemplateCategorySerializer
+    filter_backends = [SearchFilter]
+    search_fields = ['$name', ]
+
+
 class TransactionTemplateViewSet(viewsets.ModelViewSet):
     """
     REST API View set.
@@ -139,6 +153,8 @@ class TransactionTemplateViewSet(viewsets.ModelViewSet):
     """
     queryset = TransactionTemplate.objects.all()
     serializer_class = TransactionTemplateSerializer
+    filter_backends = [DjangoFilterBackend]
+    filterset_fields = ['name', 'amount', 'display', 'category', ]
 
 
 class TransactionViewSet(viewsets.ModelViewSet):
@@ -148,14 +164,6 @@ class TransactionViewSet(viewsets.ModelViewSet):
     then render it on /api/note/transaction/transaction/
     """
     queryset = Transaction.objects.all()
-    serializer_class = TransactionSerializer
-
-
-class MembershipTransactionViewSet(viewsets.ModelViewSet):
-    """
-    REST API View set.
-    The djangorestframework plugin will get all `MembershipTransaction` objects, serialize it to JSON with the given serializer,
-    then render it on /api/note/transaction/membership/
-    """
-    queryset = MembershipTransaction.objects.all()
-    serializer_class = MembershipTransactionSerializer
+    serializer_class = TransactionPolymorphicSerializer
+    filter_backends = [SearchFilter]
+    search_fields = ['$reason', ]
diff --git a/apps/note/fixtures/initial.json b/apps/note/fixtures/initial.json
index f80332c08a523081c54f7e43bdc644914f1615bf..3654fa2f5f24c17498de4452295d1a899d798f1b 100644
--- a/apps/note/fixtures/initial.json
+++ b/apps/note/fixtures/initial.json
@@ -3,7 +3,7 @@
         "model": "note.note",
         "pk": 1,
         "fields": {
-            "polymorphic_ctype": 39,
+            "polymorphic_ctype": 40,
             "balance": 0,
             "is_active": true,
             "display_image": "",
@@ -14,7 +14,7 @@
         "model": "note.note",
         "pk": 2,
         "fields": {
-            "polymorphic_ctype": 39,
+            "polymorphic_ctype": 40,
             "balance": 0,
             "is_active": true,
             "display_image": "",
@@ -25,7 +25,7 @@
         "model": "note.note",
         "pk": 3,
         "fields": {
-            "polymorphic_ctype": 39,
+            "polymorphic_ctype": 40,
             "balance": 0,
             "is_active": true,
             "display_image": "",
@@ -36,7 +36,7 @@
         "model": "note.note",
         "pk": 4,
         "fields": {
-            "polymorphic_ctype": 39,
+            "polymorphic_ctype": 40,
             "balance": 0,
             "is_active": true,
             "display_image": "",
@@ -47,7 +47,7 @@
         "model": "note.note",
         "pk": 5,
         "fields": {
-            "polymorphic_ctype": 38,
+            "polymorphic_ctype": 39,
             "balance": 0,
             "is_active": true,
             "display_image": "",
@@ -58,7 +58,7 @@
         "model": "note.note",
         "pk": 6,
         "fields": {
-            "polymorphic_ctype": 38,
+            "polymorphic_ctype": 39,
             "balance": 0,
             "is_active": true,
             "display_image": "",
diff --git a/apps/note/models/notes.py b/apps/note/models/notes.py
index 70810ad897341bd795f5d0981d5f90e63df3344c..b6b00aa8ec91fedda1449a20948625f4ea8256e1 100644
--- a/apps/note/models/notes.py
+++ b/apps/note/models/notes.py
@@ -235,7 +235,7 @@ class Alias(models.Model):
         try:
             sim_alias = Alias.objects.get(normalized_name=normalized_name)
             if self != sim_alias:
-                raise ValidationError(_('An alias with a similar name already exists: {} '.format(sim_alias)),
+                raise ValidationError(_('An alias with a similar name already exists: {} ').format(sim_alias),
                                       code="same_alias"
                                       )
         except Alias.DoesNotExist:
diff --git a/apps/note/templatetags/getenv.py b/apps/note/templatetags/getenv.py
new file mode 100644
index 0000000000000000000000000000000000000000..c133cb8ff4df0a1bfe11ec7726d604907ecde3d4
--- /dev/null
+++ b/apps/note/templatetags/getenv.py
@@ -0,0 +1,14 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from django import template
+
+import os
+
+
+def getenv(value):
+    return os.getenv(value)
+
+
+register = template.Library()
+register.filter('getenv', getenv)
diff --git a/apps/note/views.py b/apps/note/views.py
index fb5e98c5356d4259ad9086ea004c1dff22e77b24..16e2e39b9ea04b21894dc30bd8431902cd38a459 100644
--- a/apps/note/views.py
+++ b/apps/note/views.py
@@ -69,7 +69,7 @@ class NoteAutocomplete(autocomplete.Select2QuerySetView):
 
         # self.q est le paramètre de la recherche
         if self.q:
-            qs = qs.filter(Q(name__regex=self.q) | Q(normalized_name__regex=Alias.normalize(self.q))) \
+            qs = qs.filter(Q(name__regex="^" + self.q) | Q(normalized_name__regex="^" + Alias.normalize(self.q))) \
                 .order_by('normalized_name').distinct()
 
         # Filtrage par type de note (user, club, special)
@@ -141,7 +141,7 @@ class ConsoView(LoginRequiredMixin, SingleTableView):
         context = super().get_context_data(**kwargs)
         context['transaction_templates'] = TransactionTemplate.objects.filter(display=True) \
             .order_by('category')
-        context['title'] = _("Consommations")
+        context['title'] = _("Consumptions")
 
         # select2 compatibility
         context['no_cache'] = True
diff --git a/entrypoint.sh b/entrypoint.sh
index f05e962ae116b4831ea506704b828ab9c5988748..e5a22a5a53f2f25df533f9370a89f7e77205cb93 100755
--- a/entrypoint.sh
+++ b/entrypoint.sh
@@ -2,12 +2,17 @@
 # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
+if [ -z ${NOTE_URL+x} ]; then
+  echo "Warning: your env files are not configurated."
+else
+  sed -i -e "s/example.com/$DOMAIN/g" /code/apps/member/fixtures/initial.json
+  sed -i -e "s/localhost/$NOTE_URL/g" /code/note_kfet/fixtures/initial.json
+  sed -i -e "s/\.\*/https?:\/\/$NOTE_URL\/.*/g" /code/note_kfet/fixtures/cas.json
+  sed -i -e "s/REPLACEME/La Note Kfet \\\\ud83c\\\\udf7b/g" /code/note_kfet/fixtures/cas.json
+fi
+
 python manage.py compilemessages
 python manage.py makemigrations
-
-# Wait for database
-sleep 5
 python manage.py migrate
 
-# TODO: use uwsgi in production
 python manage.py runserver 0.0.0.0:8000
diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po
index ce17f5dec70ee01323b546c196e2b94e0980babb..6c60a9fe82dc6e00d72296ef06f2b60e71708b86 100644
--- a/locale/de/LC_MESSAGES/django.po
+++ b/locale/de/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-03-07 18:01+0100\n"
+"POT-Creation-Date: 2020-03-11 11:44+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -24,7 +24,7 @@ msgstr ""
 
 #: apps/activity/models.py:19 apps/activity/models.py:44
 #: apps/member/models.py:60 apps/member/models.py:111
-#: apps/note/models/notes.py:187 apps/note/models/transactions.py:24
+#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
 #: apps/note/models/transactions.py:44 templates/member/profile_detail.html:15
 msgid "name"
 msgstr ""
@@ -49,7 +49,7 @@ msgstr ""
 msgid "description"
 msgstr ""
 
-#: apps/activity/models.py:54 apps/note/models/notes.py:163
+#: apps/activity/models.py:54 apps/note/models/notes.py:164
 #: apps/note/models/transactions.py:62
 msgid "type"
 msgstr ""
@@ -90,7 +90,7 @@ msgstr ""
 msgid "Logs"
 msgstr ""
 
-#: apps/logs/models.py:21 apps/note/models/notes.py:116
+#: apps/logs/models.py:21 apps/note/models/notes.py:117
 msgid "user"
 msgstr ""
 
@@ -114,15 +114,27 @@ msgstr ""
 msgid "new data"
 msgstr ""
 
-#: apps/logs/models.py:59
+#: apps/logs/models.py:60
+msgid "create"
+msgstr ""
+
+#: apps/logs/models.py:61
+msgid "edit"
+msgstr ""
+
+#: apps/logs/models.py:62
+msgid "delete"
+msgstr ""
+
+#: apps/logs/models.py:65
 msgid "action"
 msgstr ""
 
-#: apps/logs/models.py:67
+#: apps/logs/models.py:73
 msgid "timestamp"
 msgstr ""
 
-#: apps/logs/models.py:71
+#: apps/logs/models.py:77
 msgid "Logs cannot be destroyed."
 msgstr ""
 
@@ -188,7 +200,7 @@ msgid ""
 "members can renew their membership."
 msgstr ""
 
-#: apps/member/models.py:93 apps/note/models/notes.py:138
+#: apps/member/models.py:93 apps/note/models/notes.py:139
 msgid "club"
 msgstr ""
 
@@ -237,7 +249,7 @@ msgstr ""
 msgid "Account #%(id)s: %(username)s"
 msgstr ""
 
-#: apps/member/views.py:200
+#: apps/member/views.py:202
 msgid "Alias successfully deleted"
 msgstr ""
 
@@ -250,127 +262,127 @@ msgstr ""
 msgid "destination"
 msgstr ""
 
-#: apps/note/apps.py:14 apps/note/models/notes.py:57
+#: apps/note/apps.py:14 apps/note/models/notes.py:58
 msgid "note"
 msgstr ""
 
-#: apps/note/forms.py:26
+#: apps/note/forms.py:20
 msgid "New Alias"
 msgstr ""
 
-#: apps/note/forms.py:31
+#: apps/note/forms.py:25
 msgid "select an image"
 msgstr ""
 
-#: apps/note/forms.py:32
+#: apps/note/forms.py:26
 msgid "Maximal size: 2MB"
 msgstr ""
 
-#: apps/note/forms.py:77
+#: apps/note/forms.py:70
 msgid "Source and destination must be different."
 msgstr ""
 
-#: apps/note/models/notes.py:26
+#: apps/note/models/notes.py:27
 msgid "account balance"
 msgstr ""
 
-#: apps/note/models/notes.py:27
+#: apps/note/models/notes.py:28
 msgid "in centimes, money credited for this instance"
 msgstr ""
 
-#: apps/note/models/notes.py:31
+#: apps/note/models/notes.py:32
 msgid "last negative date"
 msgstr ""
 
-#: apps/note/models/notes.py:32
+#: apps/note/models/notes.py:33
 msgid "last time the balance was negative"
 msgstr ""
 
-#: apps/note/models/notes.py:37
+#: apps/note/models/notes.py:38
 msgid "active"
 msgstr ""
 
-#: apps/note/models/notes.py:40
+#: apps/note/models/notes.py:41
 msgid ""
 "Designates whether this note should be treated as active. Unselect this "
 "instead of deleting notes."
 msgstr ""
 
-#: apps/note/models/notes.py:44
+#: apps/note/models/notes.py:45
 msgid "display image"
 msgstr ""
 
-#: apps/note/models/notes.py:52 apps/note/models/transactions.py:102
+#: apps/note/models/notes.py:53 apps/note/models/transactions.py:102
 msgid "created at"
 msgstr ""
 
-#: apps/note/models/notes.py:58
+#: apps/note/models/notes.py:59
 msgid "notes"
 msgstr ""
 
-#: apps/note/models/notes.py:66
+#: apps/note/models/notes.py:67
 msgid "Note"
 msgstr ""
 
-#: apps/note/models/notes.py:76 apps/note/models/notes.py:100
+#: apps/note/models/notes.py:77 apps/note/models/notes.py:101
 msgid "This alias is already taken."
 msgstr ""
 
-#: apps/note/models/notes.py:120
+#: apps/note/models/notes.py:121
 msgid "one's note"
 msgstr ""
 
-#: apps/note/models/notes.py:121
+#: apps/note/models/notes.py:122
 msgid "users note"
 msgstr ""
 
-#: apps/note/models/notes.py:127
+#: apps/note/models/notes.py:128
 #, python-format
 msgid "%(user)s's note"
 msgstr ""
 
-#: apps/note/models/notes.py:142
+#: apps/note/models/notes.py:143
 msgid "club note"
 msgstr ""
 
-#: apps/note/models/notes.py:143
+#: apps/note/models/notes.py:144
 msgid "clubs notes"
 msgstr ""
 
-#: apps/note/models/notes.py:149
+#: apps/note/models/notes.py:150
 #, python-format
 msgid "Note of %(club)s club"
 msgstr ""
 
-#: apps/note/models/notes.py:169
+#: apps/note/models/notes.py:170
 msgid "special note"
 msgstr ""
 
-#: apps/note/models/notes.py:170
+#: apps/note/models/notes.py:171
 msgid "special notes"
 msgstr ""
 
-#: apps/note/models/notes.py:193
+#: apps/note/models/notes.py:194
 msgid "Invalid alias"
 msgstr ""
 
-#: apps/note/models/notes.py:209
+#: apps/note/models/notes.py:210
 msgid "alias"
 msgstr ""
 
-#: apps/note/models/notes.py:210 templates/member/profile_detail.html:37
+#: apps/note/models/notes.py:211 templates/member/profile_detail.html:37
 msgid "aliases"
 msgstr ""
 
-#: apps/note/models/notes.py:228
+#: apps/note/models/notes.py:229
 msgid "Alias is too long."
 msgstr ""
 
-#: apps/note/models/notes.py:233
+#: apps/note/models/notes.py:234
 msgid "An alias with a similar name already exists: {} "
 msgstr ""
 
-#: apps/note/models/notes.py:242
+#: apps/note/models/notes.py:243
 msgid "You can't delete your main alias."
 msgstr ""
 
@@ -422,11 +434,11 @@ msgstr ""
 msgid "transactions"
 msgstr ""
 
-#: apps/note/models/transactions.py:184
+#: apps/note/models/transactions.py:185
 msgid "membership transaction"
 msgstr ""
 
-#: apps/note/models/transactions.py:185
+#: apps/note/models/transactions.py:186
 msgid "membership transactions"
 msgstr ""
 
@@ -434,34 +446,54 @@ msgstr ""
 msgid "Transfer money from your account to one or others"
 msgstr ""
 
-#: apps/note/views.py:138
+#: apps/note/views.py:139
 msgid "Consommations"
 msgstr ""
 
-#: note_kfet/settings/base.py:162
+#: note_kfet/settings/__init__.py:63
+msgid ""
+"The Central Authentication Service grants you access to most of our websites "
+"by authenticating only once, so you don't need to type your credentials "
+"again unless your session expires or you logout."
+msgstr ""
+
+#: note_kfet/settings/base.py:156
 msgid "German"
 msgstr ""
 
-#: note_kfet/settings/base.py:163
+#: note_kfet/settings/base.py:157
 msgid "English"
 msgstr ""
 
-#: note_kfet/settings/base.py:164
+#: note_kfet/settings/base.py:158
 msgid "French"
 msgstr ""
 
-#: note_kfet/settings/base.py:215
-msgid ""
-"The Central Authentication Service grants you access to most of our websites "
-"by authenticating only once, so you don't need to type your credentials "
-"again unless your session expires or you logout."
-msgstr ""
-
 #: templates/base.html:13
 msgid "The ENS Paris-Saclay BDE note."
 msgstr ""
 
-#: templates/cas_server/base.html:7 templates/cas_server/base.html:26
+#: templates/base.html:70
+msgid "Consumptions"
+msgstr ""
+
+#: templates/base.html:73
+msgid "Clubs"
+msgstr ""
+
+#: templates/base.html:76
+msgid "Activities"
+msgstr ""
+
+#: templates/base.html:79
+msgid "Button"
+msgstr ""
+
+#: templates/base.html:82 templates/note/transaction_form.html:35
+msgid "Transfer"
+msgstr ""
+
+#: templates/cas_server/base.html:7
 msgid "Central Authentication Service"
 msgstr ""
 
@@ -511,6 +543,15 @@ msgstr ""
 msgid "Connect to the service"
 msgstr ""
 
+#: templates/django_filters/rest_framework/crispy_form.html:4
+#: templates/django_filters/rest_framework/form.html:2
+msgid "Field filters"
+msgstr ""
+
+#: templates/django_filters/rest_framework/form.html:5
+msgid "Submit"
+msgstr ""
+
 #: templates/member/club_detail.html:10
 msgid "Membership starts on"
 msgstr ""
@@ -583,10 +624,6 @@ msgstr ""
 msgid "Sign Up"
 msgstr ""
 
-#: templates/note/transaction_form.html:35
-msgid "Transfer"
-msgstr ""
-
 #: templates/registration/logged_out.html:8
 msgid "Thanks for spending some quality time with the Web site today."
 msgstr ""
@@ -596,7 +633,7 @@ msgid "Log in again"
 msgstr ""
 
 #: templates/registration/login.html:7 templates/registration/login.html:8
-#: templates/registration/login.html:22
+#: templates/registration/login.html:26
 #: templates/registration/password_reset_complete.html:10
 msgid "Log in"
 msgstr ""
@@ -608,7 +645,7 @@ msgid ""
 "page. Would you like to login to a different account?"
 msgstr ""
 
-#: templates/registration/login.html:23
+#: templates/registration/login.html:27
 msgid "Forgotten your password or username?"
 msgstr ""
 
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 3a8cfb792bee0b09b3696c63283353d8772ac11d..05836a54d16fd04122280d387ccd777d9024271c 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -3,7 +3,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-03-07 18:01+0100\n"
+"POT-Creation-Date: 2020-03-11 11:44+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -19,7 +19,7 @@ msgstr "activité"
 
 #: apps/activity/models.py:19 apps/activity/models.py:44
 #: apps/member/models.py:60 apps/member/models.py:111
-#: apps/note/models/notes.py:187 apps/note/models/transactions.py:24
+#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
 #: apps/note/models/transactions.py:44 templates/member/profile_detail.html:15
 msgid "name"
 msgstr "nom"
@@ -44,7 +44,7 @@ msgstr "types d'activité"
 msgid "description"
 msgstr "description"
 
-#: apps/activity/models.py:54 apps/note/models/notes.py:163
+#: apps/activity/models.py:54 apps/note/models/notes.py:164
 #: apps/note/models/transactions.py:62
 msgid "type"
 msgstr "type"
@@ -85,15 +85,13 @@ msgstr ""
 msgid "Logs"
 msgstr ""
 
-#: apps/logs/models.py:21 apps/note/models/notes.py:116
+#: apps/logs/models.py:21 apps/note/models/notes.py:117
 msgid "user"
 msgstr "utilisateur"
 
 #: apps/logs/models.py:27
-#, fuzzy
-#| msgid "address"
 msgid "IP Address"
-msgstr "adresse"
+msgstr "Adresse IP"
 
 #: apps/logs/models.py:35
 msgid "model"
@@ -108,22 +106,30 @@ msgid "previous data"
 msgstr "Données précédentes"
 
 #: apps/logs/models.py:52
-#, fuzzy
-#| msgid "end date"
 msgid "new data"
 msgstr "Nouvelles données"
 
-#: apps/logs/models.py:59
-#, fuzzy
-#| msgid "section"
+#: apps/logs/models.py:60
+msgid "create"
+msgstr "Créer"
+
+#: apps/logs/models.py:61
+msgid "edit"
+msgstr "Modifier"
+
+#: apps/logs/models.py:62
+msgid "delete"
+msgstr "Supprimer"
+
+#: apps/logs/models.py:65
 msgid "action"
 msgstr "Action"
 
-#: apps/logs/models.py:67
+#: apps/logs/models.py:73
 msgid "timestamp"
 msgstr "Date"
 
-#: apps/logs/models.py:71
+#: apps/logs/models.py:77
 msgid "Logs cannot be destroyed."
 msgstr "Les logs ne peuvent pas être détruits."
 
@@ -193,10 +199,16 @@ msgstr ""
 "Combien de temps l'adhésion peut durer après le 1er Janvier de l'année "
 "suivante avant que les adhérents peuvent renouveler leur adhésion."
 
-#: apps/member/models.py:93 apps/note/models/notes.py:138
+#: apps/member/models.py:93 apps/note/models/notes.py:139
 msgid "club"
 msgstr "club"
 
+msgid "New club"
+msgstr "Nouveau club"
+
+msgid "Clubs list"
+msgstr "Liste des clubs"
+
 #: apps/member/models.py:94
 msgid "clubs"
 msgstr "clubs"
@@ -242,9 +254,9 @@ msgstr "Un alias avec un nom similaire existe déjà."
 msgid "Account #%(id)s: %(username)s"
 msgstr "Compte n°%(id)s : %(username)s"
 
-#: apps/member/views.py:200
+#: apps/member/views.py:202
 msgid "Alias successfully deleted"
-msgstr ""
+msgstr "L'alias a bien été supprimé"
 
 #: apps/note/admin.py:120 apps/note/models/transactions.py:93
 msgid "source"
@@ -255,132 +267,128 @@ msgstr "source"
 msgid "destination"
 msgstr "destination"
 
-#: apps/note/apps.py:14 apps/note/models/notes.py:57
+#: apps/note/apps.py:14 apps/note/models/notes.py:58
 msgid "note"
 msgstr "note"
 
-#: apps/note/forms.py:26
+#: apps/note/forms.py:20
 msgid "New Alias"
-msgstr ""
+msgstr "Nouvel alias"
 
-#: apps/note/forms.py:31
-#, fuzzy
-#| msgid "display image"
+#: apps/note/forms.py:25
 msgid "select an image"
-msgstr "image affichée"
+msgstr "Choisissez une image"
 
-#: apps/note/forms.py:32
+#: apps/note/forms.py:26
 msgid "Maximal size: 2MB"
-msgstr ""
+msgstr "Taille maximale : 2 Mo"
 
-#: apps/note/forms.py:77
+#: apps/note/forms.py:70
 msgid "Source and destination must be different."
 msgstr "La source et la destination doivent être différentes."
 
-#: apps/note/models/notes.py:26
+#: apps/note/models/notes.py:27
 msgid "account balance"
 msgstr "solde du compte"
 
-#: apps/note/models/notes.py:27
+#: apps/note/models/notes.py:28
 msgid "in centimes, money credited for this instance"
 msgstr "en centimes, argent crédité pour cette instance"
 
-#: apps/note/models/notes.py:31
+#: apps/note/models/notes.py:32
 msgid "last negative date"
 msgstr "dernier date de négatif"
 
-#: apps/note/models/notes.py:32
+#: apps/note/models/notes.py:33
 msgid "last time the balance was negative"
 msgstr "dernier instant où la note était en négatif"
 
-#: apps/note/models/notes.py:37
+#: apps/note/models/notes.py:38
 msgid "active"
 msgstr "actif"
 
-#: apps/note/models/notes.py:40
+#: apps/note/models/notes.py:41
 msgid ""
 "Designates whether this note should be treated as active. Unselect this "
 "instead of deleting notes."
 msgstr ""
 "Indique si la note est active. Désactiver cela plutôt que supprimer la note."
 
-#: apps/note/models/notes.py:44
+#: apps/note/models/notes.py:45
 msgid "display image"
 msgstr "image affichée"
 
-#: apps/note/models/notes.py:52 apps/note/models/transactions.py:102
+#: apps/note/models/notes.py:53 apps/note/models/transactions.py:102
 msgid "created at"
 msgstr "créée le"
 
-#: apps/note/models/notes.py:58
+#: apps/note/models/notes.py:59
 msgid "notes"
 msgstr "notes"
 
-#: apps/note/models/notes.py:66
+#: apps/note/models/notes.py:67
 msgid "Note"
 msgstr "Note"
 
-#: apps/note/models/notes.py:76 apps/note/models/notes.py:100
+#: apps/note/models/notes.py:77 apps/note/models/notes.py:101
 msgid "This alias is already taken."
 msgstr "Cet alias est déjà pris."
 
-#: apps/note/models/notes.py:120
+#: apps/note/models/notes.py:121
 msgid "one's note"
 msgstr "note d'un utilisateur"
 
-#: apps/note/models/notes.py:121
+#: apps/note/models/notes.py:122
 msgid "users note"
 msgstr "notes des utilisateurs"
 
-#: apps/note/models/notes.py:127
+#: apps/note/models/notes.py:128
 #, python-format
 msgid "%(user)s's note"
 msgstr "Note de %(user)s"
 
-#: apps/note/models/notes.py:142
+#: apps/note/models/notes.py:143
 msgid "club note"
 msgstr "note d'un club"
 
-#: apps/note/models/notes.py:143
+#: apps/note/models/notes.py:144
 msgid "clubs notes"
 msgstr "notes des clubs"
 
-#: apps/note/models/notes.py:149
+#: apps/note/models/notes.py:150
 #, python-format
 msgid "Note of %(club)s club"
 msgstr "Note du club %(club)s"
 
-#: apps/note/models/notes.py:169
+#: apps/note/models/notes.py:170
 msgid "special note"
 msgstr "note spéciale"
 
-#: apps/note/models/notes.py:170
+#: apps/note/models/notes.py:171
 msgid "special notes"
 msgstr "notes spéciales"
 
-#: apps/note/models/notes.py:193
+#: apps/note/models/notes.py:194
 msgid "Invalid alias"
 msgstr "Alias invalide"
 
-#: apps/note/models/notes.py:209
+#: apps/note/models/notes.py:210
 msgid "alias"
 msgstr "alias"
 
-#: apps/note/models/notes.py:210 templates/member/profile_detail.html:37
+#: apps/note/models/notes.py:211 templates/member/profile_detail.html:37
 msgid "aliases"
 msgstr "alias"
 
-#: apps/note/models/notes.py:228
+#: apps/note/models/notes.py:229
 msgid "Alias is too long."
 msgstr "L'alias est trop long."
 
-#: apps/note/models/notes.py:233
-#, fuzzy
-#| msgid "An alias with a similar name already exists:"
+#: apps/note/models/notes.py:234
 msgid "An alias with a similar name already exists: {} "
-msgstr "Un alias avec un nom similaire existe déjà."
+msgstr "Un alias avec un nom similaire existe déjà : {}"
 
-#: apps/note/models/notes.py:242
+#: apps/note/models/notes.py:243
 msgid "You can't delete your main alias."
 msgstr "Vous ne pouvez pas supprimer votre alias principal."
 
@@ -393,7 +401,6 @@ msgid "transaction categories"
 msgstr "catégories de transaction"
 
 #: apps/note/models/transactions.py:47
-#, fuzzy
 msgid "A template with this name already exist"
 msgstr "Un modèle de transaction avec un nom similaire existe déjà."
 
@@ -433,11 +440,11 @@ msgstr "transaction"
 msgid "transactions"
 msgstr "transactions"
 
-#: apps/note/models/transactions.py:184
+#: apps/note/models/transactions.py:185
 msgid "membership transaction"
 msgstr "transaction d'adhésion"
 
-#: apps/note/models/transactions.py:185
+#: apps/note/models/transactions.py:186
 msgid "membership transactions"
 msgstr "transactions d'adhésion"
 
@@ -445,34 +452,53 @@ msgstr "transactions d'adhésion"
 msgid "Transfer money from your account to one or others"
 msgstr "Transfert d'argent de ton compte vers un ou plusieurs autres"
 
-#: apps/note/views.py:138
-msgid "Consommations"
-msgstr "transactions"
+#: note_kfet/settings/__init__.py:63
+msgid ""
+"The Central Authentication Service grants you access to most of our websites "
+"by authenticating only once, so you don't need to type your credentials "
+"again unless your session expires or you logout."
+msgstr ""
 
-#: note_kfet/settings/base.py:162
+#: note_kfet/settings/base.py:156
 msgid "German"
 msgstr ""
 
-#: note_kfet/settings/base.py:163
+#: note_kfet/settings/base.py:157
 msgid "English"
 msgstr ""
 
-#: note_kfet/settings/base.py:164
+#: note_kfet/settings/base.py:158
 msgid "French"
 msgstr ""
 
-#: note_kfet/settings/base.py:215
-msgid ""
-"The Central Authentication Service grants you access to most of our websites "
-"by authenticating only once, so you don't need to type your credentials "
-"again unless your session expires or you logout."
-msgstr ""
-
 #: templates/base.html:13
 msgid "The ENS Paris-Saclay BDE note."
 msgstr "La note du BDE de l'ENS Paris-Saclay."
 
-#: templates/cas_server/base.html:7 templates/cas_server/base.html:26
+#: templates/base.html:70
+msgid "Consumptions"
+msgstr "Consommations"
+
+#: templates/base.html:73
+msgid "Clubs"
+msgstr "Clubs"
+
+#: templates/base.html:76
+msgid "Activities"
+msgstr "Activités"
+
+#: templates/base.html:79
+msgid "Buttons"
+msgstr "Boutons"
+
+msgid "Buttons list"
+msgstr "Liste des boutons"
+
+#: templates/base.html:82 templates/note/transaction_form.html:35
+msgid "Transfer"
+msgstr "Virement"
+
+#: templates/cas_server/base.html:7
 msgid "Central Authentication Service"
 msgstr ""
 
@@ -510,11 +536,11 @@ msgstr ""
 
 #: templates/cas_server/login.html:11
 msgid ""
-"If you don't have any Note Kfet account, please follow <a href='/accounts"
-"/signup'>this link to sign up</a>."
+"If you don't have any Note Kfet account, please follow <a href='/accounts/"
+"signup'>this link to sign up</a>."
 msgstr ""
-"Si vous n'avez pas de compte Note Kfet, veuillez suivre <a href='/accounts"
-"/signup'>ce lien pour vous inscrire</a>."
+"Si vous n'avez pas de compte Note Kfet, veuillez suivre <a href='/accounts/"
+"signup'>ce lien pour vous inscrire</a>."
 
 #: templates/cas_server/login.html:17
 msgid "Login"
@@ -524,6 +550,15 @@ msgstr ""
 msgid "Connect to the service"
 msgstr ""
 
+#: templates/django_filters/rest_framework/crispy_form.html:4
+#: templates/django_filters/rest_framework/form.html:2
+msgid "Field filters"
+msgstr ""
+
+#: templates/django_filters/rest_framework/form.html:5
+msgid "Submit"
+msgstr ""
+
 #: templates/member/club_detail.html:10
 msgid "Membership starts on"
 msgstr "L'adhésion commence le"
@@ -557,10 +592,8 @@ msgid "Regenerate token"
 msgstr "Regénérer le jeton"
 
 #: templates/member/profile_alias.html:10
-#, fuzzy
-#| msgid "alias"
 msgid "Add alias"
-msgstr "alias"
+msgstr "Ajouter un alias"
 
 #: templates/member/profile_detail.html:15
 msgid "first name"
@@ -583,10 +616,8 @@ msgid "Manage auth token"
 msgstr "Gérer les jetons d'authentification"
 
 #: templates/member/profile_detail.html:49
-#, fuzzy
-#| msgid "Update Profile"
 msgid "View Profile"
-msgstr "Modifier le profil"
+msgstr "Voir le profil"
 
 #: templates/member/profile_detail.html:62
 msgid "View my memberships"
@@ -596,13 +627,10 @@ msgstr "Voir mes adhésions"
 msgid "Save Changes"
 msgstr "Sauvegarder les changements"
 
+#: templates/member/signup.html:8
 #: templates/member/signup.html:14
-msgid "Sign Up"
-msgstr ""
-
-#: templates/note/transaction_form.html:35
-msgid "Transfer"
-msgstr "Virement"
+msgid "Sign up"
+msgstr "Inscription"
 
 #: templates/registration/logged_out.html:8
 msgid "Thanks for spending some quality time with the Web site today."
@@ -613,7 +641,7 @@ msgid "Log in again"
 msgstr ""
 
 #: templates/registration/login.html:7 templates/registration/login.html:8
-#: templates/registration/login.html:22
+#: templates/registration/login.html:26
 #: templates/registration/password_reset_complete.html:10
 msgid "Log in"
 msgstr ""
@@ -625,7 +653,7 @@ msgid ""
 "page. Would you like to login to a different account?"
 msgstr ""
 
-#: templates/registration/login.html:23
+#: templates/registration/login.html:27
 msgid "Forgotten your password or username?"
 msgstr ""
 
diff --git a/note_kfet/settings/__init__.py b/note_kfet/settings/__init__.py
index 6d8715990f8c69441999acbe6c7ed8430670d6b9..28935deba3ee7ba6fc7aeb9fa6d7f5ea383a2623 100644
--- a/note_kfet/settings/__init__.py
+++ b/note_kfet/settings/__init__.py
@@ -1,4 +1,9 @@
+# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from django.utils.translation import gettext_lazy as _
 import re
+
 from .base import *
 
 
@@ -30,10 +35,6 @@ read_env()
 app_stage = os.environ.get('DJANGO_APP_STAGE', 'dev')
 if app_stage == 'prod':
     from .production import *
-
-    DATABASES["default"]["PASSWORD"] = os.environ.get('DJANGO_DB_PASSWORD', 'CHANGE_ME_IN_ENV_SETTINGS')
-    SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'CHANGE_ME_IN_ENV_SETTINGS')
-    ALLOWED_HOSTS = [os.environ.get('ALLOWED_HOSTS', 'localhost')]
 else:
     from .development import *
 
@@ -46,12 +47,14 @@ except ImportError:
 if "cas" in INSTALLED_APPS:
     MIDDLEWARE += ['cas.middleware.CASMiddleware']
     # CAS Settings
+    CAS_SERVER_URL = "https://" + os.getenv("NOTE_URL", "note.example.com") + "/cas/"
     CAS_AUTO_CREATE_USER = False
     CAS_LOGO_URL = "/static/img/Saperlistpopette.png"
     CAS_FAVICON_URL = "/static/favicon/favicon-32x32.png"
     CAS_SHOW_SERVICE_MESSAGES = True
     CAS_SHOW_POWERED = False
     CAS_REDIRECT_TO_LOGIN_AFTER_LOGOUT = False
+    CAS_PROVIDE_URL_TO_LOGOUT = True
     CAS_INFO_MESSAGES = {
         "cas_explained": {
             "message": _(
@@ -68,7 +71,11 @@ if "cas" in INSTALLED_APPS:
         'cas_explained',
     ]
     AUTHENTICATION_BACKENDS += ('cas.backends.CASBackend',)
-    
+
+
+if "logs" in INSTALLED_APPS:
+    MIDDLEWARE += ('logs.middlewares.LogsMiddleware',)
+
 if "debug_toolbar" in INSTALLED_APPS:
-    MIDDLEWARE.insert(1,"debug_toolbar.middleware.DebugToolbarMiddleware")
-    INTERNAL_IPS = [ '127.0.0.1']
+    MIDDLEWARE.insert(1, "debug_toolbar.middleware.DebugToolbarMiddleware")
+    INTERNAL_IPS = ['127.0.0.1']
diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py
index 4fe12fbf2df1323b9dddd7c4acd88752654fc2b3..0694390d778e3b65f33bfe3c191251bb844bb87e 100644
--- a/note_kfet/settings/base.py
+++ b/note_kfet/settings/base.py
@@ -39,6 +39,8 @@ INSTALLED_APPS = [
     'polymorphic',
     'crispy_forms',
     'django_tables2',
+    'cas_server',
+    'cas',
     # Django contrib
     'django.contrib.admin',
     'django.contrib.admindocs',
@@ -135,11 +137,14 @@ REST_FRAMEWORK = {
     # or allow read-only access for unauthenticated users.
     'DEFAULT_PERMISSION_CLASSES': [
         # TODO Maybe replace it with our custom permissions system
-        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
+        'rest_framework.permissions.DjangoModelPermissions',
     ],
     'DEFAULT_AUTHENTICATION_CLASSES': [
+        'rest_framework.authentication.SessionAuthentication',
         'rest_framework.authentication.TokenAuthentication',
-    ]
+    ],
+    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
+    'PAGE_SIZE': 20,
 }
 
 # Internationalization
diff --git a/note_kfet/settings/development.py b/note_kfet/settings/development.py
index cf738f33a75fc584d5c74d9dfe4bb479d95ee939..66ad4fd44ed80b718cb1b430d9ad97b6692b6ba5 100644
--- a/note_kfet/settings/development.py
+++ b/note_kfet/settings/development.py
@@ -17,12 +17,24 @@ import os
 # https://docs.djangoproject.com/en/2.2/ref/settings/#databases
 from . import *
 
-DATABASES = {
-    'default': {
-        'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+if os.getenv("DJANGO_DEV_STORE_METHOD", "sqllite") == "postgresql":
+    DATABASES = {
+        'default': {
+            'ENGINE': 'django.db.backends.postgresql_psycopg2',
+            'NAME': os.environ.get('DJANGO_DB_NAME', 'note_db'),
+            'USER': os.environ.get('DJANGO_DB_USER', 'note'),
+            'PASSWORD': os.environ.get('DJANGO_DB_PASSWORD', 'CHANGE_ME_IN_ENV_SETTINGS'),
+            'HOST': os.environ.get('DJANGO_DB_HOST', 'localhost'),
+            'PORT': os.environ.get('DJANGO_DB_PORT', ''),  # Use default port
+        }
+    }
+else:
+    DATABASES = {
+        'default': {
+            'ENGINE': 'django.db.backends.sqlite3',
+            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+        }
     }
-}
 
 # Break it, fix it!
 DEBUG = True
@@ -39,7 +51,7 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
 # EMAIL_HOST_USER = 'change_me'
 # EMAIL_HOST_PASSWORD = 'change_me'
 
-SERVER_EMAIL = 'no-reply@example.org'
+SERVER_EMAIL = 'no-reply@' + os.getenv("DOMAIN", "example.com")
 
 # Security settings
 SECURE_CONTENT_TYPE_NOSNIFF = False
diff --git a/note_kfet/settings/production.py b/note_kfet/settings/production.py
index 4512dc85e813212e0c87f5ec1025f0a5f9d8e621..5be8a3b899c5093272b2db12c4aaab44060c233c 100644
--- a/note_kfet/settings/production.py
+++ b/note_kfet/settings/production.py
@@ -1,6 +1,8 @@
 # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
+import os
+
 ########################
 # Production  Settings #
 ########################
@@ -14,11 +16,11 @@
 DATABASES = {
     'default': {
         'ENGINE': 'django.db.backends.postgresql_psycopg2',
-        'NAME': 'note_db',
-        'USER': 'note',
-        'PASSWORD': 'update_in_env_variable',
-        'HOST': '127.0.0.1',
-        'PORT': '',
+        'NAME': os.environ.get('DJANGO_DB_NAME', 'note_db'),
+        'USER': os.environ.get('DJANGO_DB_USER', 'note'),
+        'PASSWORD': os.environ.get('DJANGO_DB_PASSWORD', 'CHANGE_ME_IN_ENV_SETTINGS'),
+        'HOST': os.environ.get('DJANGO_DB_HOST', 'localhost'),
+        'PORT': os.environ.get('DJANGO_DB_PORT', ''),  # Use default port
     }
 }
 
@@ -26,7 +28,9 @@ DATABASES = {
 DEBUG = True
 
 # Mandatory !
-ALLOWED_HOSTS = []
+ALLOWED_HOSTS = [os.environ.get('NOTE_URL', 'localhost')]
+
+SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'CHANGE_ME_IN_ENV_SETTINGS')
 
 # Emails
 EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
@@ -37,7 +41,7 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
 # EMAIL_HOST_USER = 'change_me'
 # EMAIL_HOST_PASSWORD = 'change_me'
 
-SERVER_EMAIL = 'no-reply@example.org'
+SERVER_EMAIL = 'no-reply@' + os.getenv("DOMAIN", "example.com")
 
 # Security settings
 SECURE_CONTENT_TYPE_NOSNIFF = False
@@ -49,4 +53,4 @@ X_FRAME_OPTIONS = 'DENY'
 SESSION_COOKIE_AGE = 60 * 60 * 3
 
 # CAS Client settings
-CAS_SERVER_URL = "https://note.crans.org/cas/"
+CAS_SERVER_URL = "https://" + os.getenv("NOTE_URL", "note.example.com") + "/cas/"
diff --git a/note_kfet/urls.py b/note_kfet/urls.py
index 896c0655b00d30f5f7ec5d71aa21841b5c87b780..da2f9d6c246833c3962b8b0727869a9585b5c4f9 100644
--- a/note_kfet/urls.py
+++ b/note_kfet/urls.py
@@ -20,8 +20,7 @@ urlpatterns = [
     path('accounts/', include('django.contrib.auth.urls')),
     path('admin/doc/', include('django.contrib.admindocs.urls')),
     path('admin/', admin.site.urls),
-    path('logs/', include('logs.urls')),
-    path('api/', include('api.urls')),  
+    path('api/', include('api.urls')),
 ]
 
 urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
@@ -37,8 +36,8 @@ if "cas" in settings.INSTALLED_APPS:
     from cas import views as cas_views
     urlpatterns += [
         # Include CAS Client routers
-        path('accounts/login/', cas_views.login, name='login'),
-        path('accounts/logout/', cas_views.logout, name='logout'),
+        path('accounts/login/cas/', cas_views.login, name='cas_login'),
+        path('accounts/logout/cas/', cas_views.logout, name='cas_logout'),
        
     ]
 if "debug_toolbar" in settings.INSTALLED_APPS:
diff --git a/templates/base.html b/templates/base.html
index dbe59c41e71e96e37b5356b82cab8fb18ef0cf48..d57dab8933ca1e51f182e73e66f28fedde1df727 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -1,4 +1,4 @@
-{% load static i18n pretty_money static %}
+{% load static i18n pretty_money static getenv %}
 {% comment %}
 SPDX-License-Identifier: GPL-3.0-or-later
 {% endcomment %}
@@ -75,6 +75,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
                 <li class="nav-item active">
                     <a class="nav-link" href="#"><i class="fa fa-calendar"></i> {% trans 'Activities' %}</a>
                 </li>
+                <li class="nav-item active">
+                    <a class="nav-link" href="{% url 'note:template_list' %}"><i class="fa fa-coffee"></i> {% trans 'Buttons' %}</a>
+                </li>
                 <li class="nav-item active">
                     <a class="nav-link" href="{% url 'note:transfer' %}"><i class="fa fa-exchange"></i>{% trans 'Transfer' %} </a>
                 </li>
@@ -125,7 +128,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
                       class="form-inline">
                     <span class="text-muted mr-1">
                         NoteKfet2020 &mdash;
-                        <a href="mailto:tresorie.bde@lists.crans.org"
+                        <a href="mailto:{{ "CONTACT_EMAIL" | getenv }}"
                            class="text-muted">Nous contacter</a> &mdash;
                     </span>
                     {% csrf_token %}
diff --git a/templates/django_filters/rest_framework/crispy_form.html b/templates/django_filters/rest_framework/crispy_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..171767c086cc5fe7f96816d6b0a2c2bfc50b1d08
--- /dev/null
+++ b/templates/django_filters/rest_framework/crispy_form.html
@@ -0,0 +1,5 @@
+{% load crispy_forms_tags %}
+{% load i18n %}
+
+<h2>{% trans "Field filters" %}</h2>
+{% crispy filter.form %}
diff --git a/templates/django_filters/rest_framework/form.html b/templates/django_filters/rest_framework/form.html
new file mode 100644
index 0000000000000000000000000000000000000000..b116e35317537ecf43046b79a4ca7525d1dc80c0
--- /dev/null
+++ b/templates/django_filters/rest_framework/form.html
@@ -0,0 +1,6 @@
+{% load i18n %}
+<h2>{% trans "Field filters" %}</h2>
+<form class="form" action="" method="get">
+    {{ filter.form.as_p }}
+    <button type="submit" class="btn btn-primary">{% trans "Submit" %}</button>
+</form>
diff --git a/templates/django_filters/widgets/multiwidget.html b/templates/django_filters/widgets/multiwidget.html
new file mode 100644
index 0000000000000000000000000000000000000000..089ddb20c9fccebb7562d4cb0c400ba0a6f3020c
--- /dev/null
+++ b/templates/django_filters/widgets/multiwidget.html
@@ -0,0 +1 @@
+{% for widget in widget.subwidgets %}{% include widget.template_name %}{% if forloop.first %}-{% endif %}{% endfor %}
diff --git a/templates/member/club_form.html b/templates/member/club_form.html
index 3fc2dd8be1aa4916e6425659c2b79decad67e3b9..577297bbc12eb39b0f0457ae8c65945ffc71750f 100644
--- a/templates/member/club_form.html
+++ b/templates/member/club_form.html
@@ -1,11 +1,12 @@
 {% extends "base.html" %}
 {% load static %}
+{% load i18n %}
 {% load crispy_forms_tags %}
 {% block content %}
-<p><a class="btn btn-default" href="{% url 'note:template_list' %}">Template Listing</a></p>
+<p><a class="btn btn-default" href="{% url 'note:template_list' %}">{% trans "Clubs list" %}</a></p>
 <form method="post">
 {% csrf_token %}
 {{form|crispy}}
-<button class="btn btn-primary" type="submit">Submit</button>
+<button class="btn btn-primary" type="submit">{% trans "Submit" %}</button>
 </form>
 {% endblock %}
diff --git a/templates/member/club_list.html b/templates/member/club_list.html
index f807c25ce8fd252ecf0a06b3d93e5312b351a6a3..165711136329c1a8ccbdf12880c33499541c0436 100644
--- a/templates/member/club_list.html
+++ b/templates/member/club_list.html
@@ -1,10 +1,11 @@
 {% extends "base.html" %}
 {% load render_table from django_tables2 %}
+{% load i18n %}
 {% block content %}
 
 {% render_table  table %}
 
-<a class="btn btn-primary" href="{% url 'member:club_create' %}">New Club</a>
+<a class="btn btn-primary" href="{% url 'member:club_create' %}">{% trans "New club" %}</a>
 
 {% endblock %}
 {% block extrajavascript %}
diff --git a/templates/member/signup.html b/templates/member/signup.html
index e682bd9b8be5c6c327f8b17cdf4d7a7f07a3da96..d7b3c23ef8bb0fba2baebc04e178ecf1bc59ab78 100644
--- a/templates/member/signup.html
+++ b/templates/member/signup.html
@@ -2,16 +2,16 @@
 {% extends 'base.html' %}
 {% load crispy_forms_tags %}
 {% load i18n %}
-{% block title %}Sign Up{% endblock %}
+{% block title %}{% trans "Sign up" %}{% endblock %}
 
 {% block content %}
-  <h2>Sign up</h2>
+  <h2>{% trans "Sign up" %}</h2>
   <form method="post">
       {% csrf_token %}
       {{ form|crispy }}
       {{ profile_form|crispy }}
       <button class="btn btn-success" type="submit">
-          {% trans "Sign Up" %}
+          {% trans "Sign up" %}
       </button>
   </form>
 {% endblock %}
diff --git a/templates/note/transactiontemplate_form.html b/templates/note/transactiontemplate_form.html
index 3fc2dd8be1aa4916e6425659c2b79decad67e3b9..1f9a574a050ff49056f3a6931a00636cb951b747 100644
--- a/templates/note/transactiontemplate_form.html
+++ b/templates/note/transactiontemplate_form.html
@@ -1,8 +1,9 @@
 {% extends "base.html" %}
 {% load static %}
+{% load i18n %}
 {% load crispy_forms_tags %}
 {% block content %}
-<p><a class="btn btn-default" href="{% url 'note:template_list' %}">Template Listing</a></p>
+<p><a class="btn btn-default" href="{% url 'note:template_list' %}">{% trans "Buttons list" %}</a></p>
 <form method="post">
 {% csrf_token %}
 {{form|crispy}}
diff --git a/templates/registration/login.html b/templates/registration/login.html
index 04ef8d7deb25d939ef1ca6f1eb6ab9995416ed69..5a4322d138ea110f8089d6c9a928d579740f476c 100644
--- a/templates/registration/login.html
+++ b/templates/registration/login.html
@@ -17,6 +17,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
         </p>
     {% endif %}
 
+    <div class="alert alert-info">
+        Vous pouvez aussi vous connecter via l'authentification centralisée <a href="{% url 'cas_login' %}">en suivant ce lien.</a>
+    </div>
+
     <form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
         {{ form | crispy }}
         <input type="submit" value="{% trans 'Log in' %}" class="btn btn-primary">
diff --git a/tox.ini b/tox.ini
index 7c432d55ab581b87a68e2e71ac22157d721706aa..2217b6bfbf407fc4056ac13140ae604e32bfd87f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -32,7 +32,7 @@ deps =
     pep8-naming
     pyflakes
 commands =
-    flake8 apps/activity apps/api apps/member apps/note
+    flake8 apps/activity apps/api apps/logs apps/member apps/note
 
 [flake8]
 # Ignore too many errors, should be reduced in the future