diff --git a/apps/official/BiscuIT-App-Alsijil b/apps/official/BiscuIT-App-Alsijil
index 45bf10456b2a68b6773c8c74feb0698447dd8e48..a0c50e1881df1c19cbbccc472f24b0012b2fa482 160000
--- a/apps/official/BiscuIT-App-Alsijil
+++ b/apps/official/BiscuIT-App-Alsijil
@@ -1 +1 @@
-Subproject commit 45bf10456b2a68b6773c8c74feb0698447dd8e48
+Subproject commit a0c50e1881df1c19cbbccc472f24b0012b2fa482
diff --git a/apps/official/BiscuIT-App-Chronos b/apps/official/BiscuIT-App-Chronos
index 58e71f31a69cc5dddbc676d6fc8b1b9f93820f57..fea3df1800f9cbf1b0b17f23d322fa9964d90e91 160000
--- a/apps/official/BiscuIT-App-Chronos
+++ b/apps/official/BiscuIT-App-Chronos
@@ -1 +1 @@
-Subproject commit 58e71f31a69cc5dddbc676d6fc8b1b9f93820f57
+Subproject commit fea3df1800f9cbf1b0b17f23d322fa9964d90e91
diff --git a/apps/official/BiscuIT-App-Exlibris b/apps/official/BiscuIT-App-Exlibris
index 530a8e3b69fe838d0e08c46da4b3a1600c5b2417..efdf82d5df68807ad6f03bcea598b06264f8c5df 160000
--- a/apps/official/BiscuIT-App-Exlibris
+++ b/apps/official/BiscuIT-App-Exlibris
@@ -1 +1 @@
-Subproject commit 530a8e3b69fe838d0e08c46da4b3a1600c5b2417
+Subproject commit efdf82d5df68807ad6f03bcea598b06264f8c5df
diff --git a/apps/official/BiscuIT-App-SchILD-NRW b/apps/official/BiscuIT-App-SchILD-NRW
index 3d622c220ac7979c1ba864c4da9df2fcd58cf70c..b009a2b137cf637c830fed9223e73d1b805a3580 160000
--- a/apps/official/BiscuIT-App-SchILD-NRW
+++ b/apps/official/BiscuIT-App-SchILD-NRW
@@ -1 +1 @@
-Subproject commit 3d622c220ac7979c1ba864c4da9df2fcd58cf70c
+Subproject commit b009a2b137cf637c830fed9223e73d1b805a3580
diff --git a/apps/official/BiscuIT-App-Untis b/apps/official/BiscuIT-App-Untis
index 4b4cd60ac4d1b4b9ed706550adeb3f4a669ff1b1..c437e7e151c9b16d6bddac9ef7acb3539943d6c5 160000
--- a/apps/official/BiscuIT-App-Untis
+++ b/apps/official/BiscuIT-App-Untis
@@ -1 +1 @@
-Subproject commit 4b4cd60ac4d1b4b9ed706550adeb3f4a669ff1b1
+Subproject commit c437e7e151c9b16d6bddac9ef7acb3539943d6c5
diff --git a/biscuit/core/migrations/0014_remove_unique.py b/biscuit/core/migrations/0014_remove_unique.py
new file mode 100644
index 0000000000000000000000000000000000000000..d985917972616b5c30cf700fb0333c7bf72f54da
--- /dev/null
+++ b/biscuit/core/migrations/0014_remove_unique.py
@@ -0,0 +1,23 @@
+# Generated by Django 2.2.4 on 2019-08-22 19:26
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0013_person_primary_group'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='group',
+            name='name',
+            field=models.CharField(max_length=30, verbose_name='Long name of group'),
+        ),
+        migrations.AlterField(
+            model_name='group',
+            name='short_name',
+            field=models.CharField(max_length=8, verbose_name='Short name of group'),
+        ),
+    ]
diff --git a/biscuit/core/models.py b/biscuit/core/models.py
index 500af9b0c5f5c0d22d314ad93bdb3df4f84ed583..a1991a538111f5c0a63c9ccb5164311ba9a11dc9 100644
--- a/biscuit/core/models.py
+++ b/biscuit/core/models.py
@@ -1,3 +1,5 @@
+from typing import Optional
+
 from django.contrib.auth import get_user_model
 from django.db import models
 from django.utils.translation import ugettext_lazy as _
@@ -76,6 +78,33 @@ class Person(SchoolRelated):
 
     primary_group = models.ForeignKey('Group', models.SET_NULL, null=True)
 
+    @property
+    def primary_group_short_name(self) -> Optional[str]:
+        """ Returns the short_name field of the primary
+        group related object.
+        """
+
+        if self.primary_group:
+            return self.primary_group.short_name
+    @primary_group_short_name.setter
+    def primary_group_short_name(self, value: str) -> None:
+        """ Sets the primary group related object by
+        a short name. It uses the first existing group
+        with this short name it can find, creating one
+        if it can't find one.
+        """
+
+        group, created = Group.objects.get_or_create(short_name=value,
+                                                     defaults={'name': value})
+        self.primary_group = group
+
+    def save(self, *args, **kwargs):
+        if self.primary_group:
+            if self.primary_group not in self.member_of.all():
+                self.member_of.add(self.primary_group)
+
+        return super().save(*args, **kwargs)
+
     def __str__(self) -> str:
         return '%s, %s' % (self.last_name, self.first_name)
 
@@ -89,9 +118,9 @@ class Group(SchoolRelated):
         unique_together = [['school', 'name'], ['school', 'short_name']]
 
     name = models.CharField(verbose_name=_(
-        'Long name of group'), max_length=30, unique=True)
+        'Long name of group'), max_length=30)
     short_name = models.CharField(verbose_name=_(
-        'Short name of group'), max_length=8, unique=True)
+        'Short name of group'), max_length=8)
 
     members = models.ManyToManyField('Person', related_name='member_of')
     owners = models.ManyToManyField('Person', related_name='owner_of')
diff --git a/biscuit/core/templates/core/group_full.html b/biscuit/core/templates/core/group_full.html
index d4c0854be55f523c8bd670a1956c9b4a154a6614..92965a72c15bf151f192da23cbd69372994ca473 100644
--- a/biscuit/core/templates/core/group_full.html
+++ b/biscuit/core/templates/core/group_full.html
@@ -1,5 +1,6 @@
 {% extends "core/base.html" %}
 {% load bootstrap4 font_awesome i18n staticfiles %}
+{% load render_table from django_tables2 %}
 
 {% block content %}
 <div class="col-sm-12 col-md-12">
diff --git a/biscuit/core/util/core_helpers.py b/biscuit/core/util/core_helpers.py
index 94ffde727a44c9eb516ef3b42cac38d8b2377ae3..23efbf02b06f569b9ef64c2a9443a033b7a8ad35 100644
--- a/biscuit/core/util/core_helpers.py
+++ b/biscuit/core/util/core_helpers.py
@@ -4,8 +4,6 @@ from typing import Optional, Sequence
 
 from django_global_request.middleware import get_request
 
-from ..models import School
-
 
 def get_app_packages() -> Sequence[str]:
     """ Find all packages within the biscuit.apps namespace. """
@@ -31,7 +29,8 @@ def get_app_packages() -> Sequence[str]:
     return pkgs
 
 
-def get_current_school() -> Optional[School]:
+# FIXME Use more specific result type
+def get_current_school() -> Optional:
     request = get_request()
 
     if request:
diff --git a/biscuit/core/util/messages.py b/biscuit/core/util/messages.py
index 98a273b90eab32a9de5961a5542355f2acbfebe0..7b847885567b989100b89de4c830d73f4346bb70 100644
--- a/biscuit/core/util/messages.py
+++ b/biscuit/core/util/messages.py
@@ -1,32 +1,32 @@
 import logging
-from typing import Optional
+from typing import Any, Optional
 
 from django.contrib import messages
 from django.http import HttpRequest
 
 
-def add_message(request: Optional[HttpRequest], level: int, message: str, **kwargs) -> Any:
+def add_message(request: Optional[HttpRequest], level: int, message: str, **kwargs) -> Optional[Any]:
     if request:
         return messages.add_message(request, level, message, **kwargs)
     else:
         return logging.getLogger(__name__).log(level, message)
 
 
-def debug(request: Optional[HttpRequest], message: str, **kwargs) -> Any
+def debug(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any]:
     return add_message(request, messages.DEBUG, message, **kwargs)
 
 
-def info(request: Optional[HttpRequest], message: str, **kwargs) -> Any
+def info(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any]:
     return add_message(request, messages.INFO, message, **kwargs)
 
 
-def success(request: Optional[HttpRequest], message: str, **kwargs) -> Any
+def success(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any]:
     return add_message(request, messages.SUCCESS, message, **kwargs)
 
 
-def warning(request: Optional[HttpRequest], message: str, **kwargs) -> Any
+def warning(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any]:
     return add_message(request, messages.WARNING, message, **kwargs)
 
 
-def error(request: Optional[HttpRequest], message: str, **kwargs) -> Any
+def error(request: Optional[HttpRequest], message: str, **kwargs) -> Optional[Any]:
     return add_message(request, messages.ERROR, message, **kwargs)
diff --git a/biscuit/core/views.py b/biscuit/core/views.py
index b4a4d6635468c59b628b7189ed9c090b985919ca..968e983943645aa2cc5275b2183cf63f444614ce 100644
--- a/biscuit/core/views.py
+++ b/biscuit/core/views.py
@@ -1,3 +1,5 @@
+from typing import Callable
+
 from django.contrib.auth.decorators import login_required
 from django.conf import settings
 from django.http import Http404, HttpRequest, HttpResponse
@@ -87,7 +89,7 @@ def group(request: HttpRequest, id_: int, template: str) -> HttpResponse:
     group = Group.objects.get(pk=id_)
 
     # Get members
-    persons = group.members
+    persons = group.members.all()
 
     # Build table
     persons_table = PersonsTable(persons)
diff --git a/dev.sh b/dev.sh
index 1d1f310eeb2f3e5fedd13b120ade7762f5022fc9..0dc003da156de64c8f16db13f28260080dd37dfa 100755
--- a/dev.sh
+++ b/dev.sh
@@ -1,5 +1,7 @@
 #!/bin/sh
 
+set -e
+
 remove_pip_metadata() {
     find . -type d -name pip-wheel-metadata -print0 | xargs -0r rm -rf --
 }
@@ -16,7 +18,7 @@ case "$1" in
 	remove_pip_metadata
 	poetry run ./manage.py migrate
 	poetry run ./manage.py compilemessages
-	poetry run ./manage.py collectstatic
+	poetry run ./manage.py collectstatic --no-input
 	;;
     *)
 	;;