diff --git a/app/__init__.py b/app/__init__.py
index 272a812abdce3d9224e6c09f1e7b6d104896c61f..4a689dcf949cd8c63a320307d33d3998155d1fda 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -2,11 +2,13 @@ from flask import Flask
 from flask_sqlalchemy import SQLAlchemy
 from flask_migrate import Migrate
 from flask_bootstrap import Bootstrap
+from flask_wtf.csrf import CSRFProtect
 from flask_mail import Mail
 
 # global variable initialization
 db = SQLAlchemy()
 mail = Mail()
+csrf = CSRFProtect()
 
 def create_app():
     # initialize flask app and configure
@@ -16,10 +18,12 @@ def create_app():
     # initialize Mail
     mail.init_app(app)
 
+    # initialize CSRF protection
+    csrf.init_app(app)
+
     # initialize ORM
     db.init_app(app)
 
-
     # add database migration from flask-migrate
     Migrate(app, db)
 
@@ -39,9 +43,4 @@ def create_app():
     from .bouncer import bouncer_bp
     app.register_blueprint(bouncer_bp)
 
-    # @app.route('/')
-    # def hello_world():
-    #     print(app.config.get('TOTAL_SPOTS'))
-    #     return 'Hello, World!'
-
     return app
diff --git a/app/auth.py b/app/auth.py
index 813dfaa7061aecafe3c1bb4e71653fb463b6e77a..2dc776afd3f92cca6637da9d3ba195571d423ce8 100644
--- a/app/auth.py
+++ b/app/auth.py
@@ -8,13 +8,10 @@ from .models import User
 def login_required(f):
     """
     Requires that the user is logged in.
-
-    This is a wrapper for the @login_required decorator.
-
-    Error 403: shwon if trying to access with an api key (Authorization header).
     """
     @wraps(f)
     def wrapped(*args, **kwargs):
+        print('test')
         if not is_authenticated():
             abort(403)
 
@@ -23,15 +20,19 @@ def login_required(f):
 
 
 def is_authenticated():
-    return 'userID' in session and User.query.get(session['userID']) is not None
+    return 'userID' in session and session['userID'] is not None and User.query.get(session['userID']) is not None
 
 
 def get_authenticated_user():
-    return User.query.get(session['userID']) if 'userID' in session else None
+    return User.query.get(session['userID']) if 'userID' in session and session['userID'] is not None else None
 
 
 def login(email, password):
+    if email is None or password is None:
+        return False
+
     user = User.query.filter(User.email == email).first()
+
     if user.check_password(password):
         session['userID'] = user._id
         return True
diff --git a/app/bouncer/views.py b/app/bouncer/views.py
index 8825957194a00076259291c959fbcdb485556b38..befea768ccf8da1e33c6133762012eb8e5aa7df0 100644
--- a/app/bouncer/views.py
+++ b/app/bouncer/views.py
@@ -3,8 +3,9 @@ from flask import flash, redirect, render_template, url_for, request, abort, mak
 from . import bouncer_bp
 from ..auth import login_required, is_authenticated, get_authenticated_user
 from ..controllers import FreeSpotController, UserController, ReservationController, RecordController
+from ..exceptions import NoFreeSpotError
 
-@bouncer_bp.route('/')
+@bouncer_bp.route('/', methods=['GET', 'POST'])
 def home():
     free_spots = FreeSpotController.get_free_spots()
 
@@ -12,6 +13,95 @@ def home():
         user = get_authenticated_user()
         reservation = ReservationController.get_active_reservation(user)
         record = RecordController.get_active_record(user)
-    
-        return make_response(render_template('bouncer/home_authenticated.html', title='Home', free_spots=free_spots, name=user.name, email=user.email))
+
+        if request.method == 'POST':
+            if request.form['action'] == 'enter':
+                try:
+                    UserController.start_record(user)
+                    flash('You are allowed to enter.')
+                    return redirect(url_for('bouncer.home'))
+                except NoFreeSpotError:
+                    flash('No free spots available! Try again later.', 'error')
+            if request.form['action'] == 'reserve':
+                try:
+                    UserController.reserve(user)
+                    flash('Your reservation has been recorded. Your request for entry will be granted immediately as long as your reservation is valid.')
+                    return redirect(url_for('bouncer.home'))
+                except NoFreeSpotError:
+                    flash('No free spots available! Try again later.', 'error')
+
+        return make_response(render_template('bouncer/home_authenticated.html', title='Home', free_spots=free_spots, user=user, reservation=reservation, record=record))
     return make_response(render_template('bouncer/home_anonymous.html', title='Home', free_spots=free_spots))
+
+@bouncer_bp.route('/confirm/leave', methods=['GET', 'POST'])
+@login_required
+def confirm_leave():
+    free_spots = FreeSpotController.get_free_spots()
+    user = get_authenticated_user()
+    record = RecordController.get_active_record(user)
+
+    if not user.is_confirmed:
+        flash('Please confirm your email address first!', 'warning')
+        return redirect(url_for('bouncer.home'))
+
+    if record is None:
+        flash('You didn\'t report that you were there.', 'warning')
+        return redirect(url_for('bouncer.home'))
+
+    if request.method == 'POST':
+        if request.form['action'] == 'leave':
+            RecordController.terminate(record)
+            flash('You have been checked out successfully.')
+            return redirect(url_for('bouncer.home'))
+
+    return make_response(render_template('bouncer/confirm_leave.html', title='Confirm: leave', user=user, free_spots=free_spots))
+
+@bouncer_bp.route('/confirm/enter', methods=['GET', 'POST'])
+@login_required
+def confirm_enter():
+    free_spots = FreeSpotController.get_free_spots()
+    user = get_authenticated_user()
+
+    if not user.is_confirmed:
+        flash('Please confirm your email address first!', 'warning')
+        return redirect(url_for('bouncer.home'))
+
+    if RecordController.has_active_record(user):
+        flash('You already reported to be there!', 'warning')
+        return redirect(url_for('bouncer.home'))
+
+    if request.method == 'POST':
+        if request.form['action'] == 'enter':
+            try:
+                UserController.start_record(user)
+                flash('You are cleared for entry.')
+                return redirect(url_for('bouncer.home'))
+            except NoFreeSpotError:
+                flash ('No free spots available! Try again later.', 'error')
+                return redirect(url_for('bouncer.home'))
+
+    return make_response(render_template('bouncer/confirm_enter.html', title='Confirm: enter', user=user, free_spots=free_spots))
+
+
+@bouncer_bp.route('/confirm/cancel', methods=['GET', 'POST'])
+@login_required
+def confirm_cancel():
+    free_spots = FreeSpotController.get_free_spots()
+    user = get_authenticated_user()
+    reservation = ReservationController.get_active_reservation(user)
+
+    if not user.is_confirmed:
+        flash('Please confirm your email address first!', 'warning')
+        return redirect(url_for('bouncer.home'))
+
+    if not reservation:
+        flash('You do not have any reservations!', 'warning')
+        return redirect(url_for('bouncer.home'))
+
+    if request.method == 'POST':
+        if request.form['action'] == 'cancel':
+            ReservationController.cancel(reservation)
+            flash('Your reservation has been cancelled.')
+            return redirect(url_for('bouncer.home'))
+
+    return make_response(render_template('bouncer/confirm_cancel.html', title='Confirm: cancel reservation', user=user, free_spots=free_spots))
diff --git a/app/controllers/free_spot.py b/app/controllers/free_spot.py
index 0b4ddc016e1e2a2606455cd44710a6df780111b3..bbd65ee9b14433533aaec80a57fba6e82826ce9f 100644
--- a/app/controllers/free_spot.py
+++ b/app/controllers/free_spot.py
@@ -1,8 +1,8 @@
 import threading
 from datetime import datetime
-from sqlalchemy import DateTime, cast, func
+from sqlalchemy import DateTime, cast, func, or_
 from flask import current_app
-from app import models
+from app.models import Record, Reservation
 from app import db
 from .lock import Lock
 from ..exceptions import NoFreeSpotError
@@ -36,14 +36,14 @@ class FreeSpotController():
         total_spots = current_app.config.get('TOTAL_SPOTS')
         now = datetime.now()
 
-        active_records_count = db.session.query(func.count(models.Record._id)) \
-            .filter(cast(models.Record.time_start,DateTime) <= now) \
-            .filter(cast(models.Record.time_end,DateTime) >= now) \
+        active_records_count = db.session.query(func.count(Record._id)) \
+            .filter(cast(Record.time_start,DateTime) <= now) \
+            .filter(or_(cast(Record.time_end,DateTime) >= now, Record.time_end == None)) \
             .scalar()
 
-        valid_reservations_count = db.session.query(func.count(models.Reservation._id)) \
-            .filter(cast(models.Reservation.time_start,DateTime) <= now) \
-            .filter(cast(models.Reservation.time_end,DateTime) >= now) \
+        valid_reservations_count = db.session.query(func.count(Reservation._id)) \
+            .filter(cast(Reservation.time_start,DateTime) <= now) \
+            .filter(cast(Reservation.time_end,DateTime) >= now) \
             .scalar()
 
 
diff --git a/app/controllers/record.py b/app/controllers/record.py
index 3a0d840bc71ce050e409733ffbe5f68d7f795779..59702025923db82e4646d567ea01711729ed957d 100644
--- a/app/controllers/record.py
+++ b/app/controllers/record.py
@@ -1,6 +1,6 @@
 import threading
 from datetime import datetime
-from sqlalchemy import DateTime, cast, func
+from sqlalchemy import DateTime, cast, func, or_
 from app import db
 from app.models import Record
 from .lock import Lock
@@ -22,7 +22,6 @@ class RecordController():
             record.user = user
             record.time_start = datetime.now()
             record.time_end = None
-            record.name = reservation.name
 
             db.session.add(record)
             db.session.commit()
@@ -31,18 +30,17 @@ class RecordController():
     @classmethod
     def create_from_reservation(cls, reservation):
         with cls.spot_lock:
-            if not user.is_confirmed:
+            if not reservation.user.is_confirmed:
                 raise UserNotConfirmedError
 
             if reservation.is_valid:
                 time_start = datetime.now()
                 reservation.time_end = time_start
 
-                record = models.Record()
+                record = Record()
                 record.user = reservation.user
                 record.time_start = time_start
                 record.time_end = None
-                record.name = reservation.name
 
                 db.session.add(record)
                 db.session.commit()
@@ -60,7 +58,8 @@ class RecordController():
         now = datetime.now()
         return Record.query \
             .filter(cast(Record.time_start,DateTime) <= now) \
-            .filter(cast(Record.time_end,DateTime) > now)
+            .filter(or_(cast(Record.time_end,DateTime) > now, Record.time_end == None)) \
+            .first()
 
 
     @classmethod
diff --git a/app/controllers/reservation.py b/app/controllers/reservation.py
index 30518fd206a835cbe6b1fb341c173e8397df74ba..1047050ae1d8c1dc145becd8d6a4d951828206c8 100644
--- a/app/controllers/reservation.py
+++ b/app/controllers/reservation.py
@@ -5,6 +5,7 @@ from flask import current_app
 from app import db
 from app.models import Reservation
 from .lock import Lock
+from .free_spot import FreeSpotController
 from ..exceptions import ReservationExpiredError, NoFreeSpotError, UserNotConfirmedError
 
 class ReservationController():
@@ -14,16 +15,15 @@ class ReservationController():
     @classmethod
     def create(cls, user):
         with cls.spot_lock:
-            cls.check_free_spots()
+            FreeSpotController.check_free_spots()
 
             if not user.is_confirmed:
                 raise UserNotConfirmedError
 
             record = Reservation()
             record.user = user
-            record.name = name
             record.time_start = datetime.now()
-            record.time_end = datetime.now() + current_app.config('RESERVATION_DURATION', timedelta(hours=1))
+            record.time_end = datetime.now() + current_app.config.get('RESERVATION_DURATION', timedelta(hours=1))
 
             db.session.add(record)
             db.session.commit()
@@ -39,7 +39,8 @@ class ReservationController():
         now = datetime.now()
         return Reservation.query \
             .filter(cast(Reservation.time_start,DateTime) <= now) \
-            .filter(cast(Reservation.time_end,DateTime) > now)
+            .filter(cast(Reservation.time_end,DateTime) > now) \
+            .first()
 
 
     @classmethod
diff --git a/app/login/views.py b/app/login/views.py
index a6aeec81bab0e76c28f8b79e7b008e9043dc59a4..e387707956ad688e71628aaf596bd810e072bc6e 100644
--- a/app/login/views.py
+++ b/app/login/views.py
@@ -2,11 +2,14 @@ from flask import flash, redirect, render_template, url_for, request, abort, mak
 
 from ..controllers.user import UserController
 from ..exceptions import UserRegistrationInvalidDataError
-from ..auth import login as auth_login, logout as auth_logout
+from ..auth import login as auth_login, logout as auth_logout, is_authenticated
 from . import login_bp
 
 @login_bp.route('/register', methods=['GET', 'POST'])
 def register():
+    if is_authenticated():
+        return redirect(url_for('bouncer.home'))
+
     errors = None
     if request.method == 'POST':
         try:
@@ -28,7 +31,7 @@ def register():
     return make_response(render_template('login/register.html', title='Registration', errors=errors))
 
 
-@login_bp.route('/confirm_email')
+@login_bp.route('/confirm/email')
 def confirm_email():
     email = request.args.get('email')
     token = request.args.get('token')
@@ -45,6 +48,9 @@ def confirm_email():
 
 @login_bp.route('/login', methods=['GET', 'POST'])
 def login():
+    if is_authenticated():
+        return redirect(url_for('bouncer.home'))
+
     if request.method == 'POST':
         if auth_login(request.form['email'], request.form['password']):
             return redirect(url_for('bouncer.home'))
diff --git a/app/models/reservation.py b/app/models/reservation.py
index f435b20aa19901e1139bac5bd7292b2bf3c0a94d..6c994b9611635e018866a72b819a9a80fafee438 100644
--- a/app/models/reservation.py
+++ b/app/models/reservation.py
@@ -19,4 +19,4 @@ class Reservation(db.Model):
 
     @property
     def is_valid(self):
-        return self.time_end - datetime.now() < timedelta(seconds=0)
+        return self.time_end - datetime.now() > timedelta(seconds=0)
diff --git a/app/templates/base_authenticated.html b/app/templates/base_authenticated.html
new file mode 100644
index 0000000000000000000000000000000000000000..f10bdb3b2b907e0f11e090d6f40d17f45235409a
--- /dev/null
+++ b/app/templates/base_authenticated.html
@@ -0,0 +1,21 @@
+{% import "bootstrap/utils.html" as utils %}
+{% extends "base.html" %}
+{% block body %}
+<div class="content-section">
+  <br/>
+  {{ utils.flashed_messages() }}
+  <br/>
+  <div class="center-narrow">
+    <h1>Bastli Bouncer</h1>
+    <br/>
+    <p>We currently have <span class="free_spots">{{ free_spots }} free spots</span> in our workshop.</p>
+    <p>
+      Welcome, {{ user.name }} ({{ user.email }}).
+      <a class="btn btn-default" role="button" href="{{ url_for('login.logout') }}">Logout</a>
+    </p>
+    <br/>
+    {% block content %}
+    {% endblock %}
+  </div>
+</div>
+{% endblock %}
diff --git a/app/templates/bouncer/confirm_cancel.html b/app/templates/bouncer/confirm_cancel.html
new file mode 100644
index 0000000000000000000000000000000000000000..f067fa26405744dd2a4982faede8d0164f4f4aa8
--- /dev/null
+++ b/app/templates/bouncer/confirm_cancel.html
@@ -0,0 +1,12 @@
+{% import "bootstrap/utils.html" as utils %}
+{% extends "base_authenticated.html" %}
+{% block content %}
+    <h2>Cancel Reservation</h2>
+    <p>Do you really want to cancel your reservation?</p>
+    <form action="" method="post">
+      <input type="hidden" name="action" value="cancel">
+      <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
+      <input class="btn btn-primary" type="submit" value="Cancel reservation now"> or 
+      <a class="btn btn-default" role="button" href="{{ url_for('bouncer.home') }}">Go back</a>
+    </form>
+{% endblock %}
diff --git a/app/templates/bouncer/confirm_enter.html b/app/templates/bouncer/confirm_enter.html
new file mode 100644
index 0000000000000000000000000000000000000000..f3b9c4e9c872d1304d14a94607393ecb8c02b57e
--- /dev/null
+++ b/app/templates/bouncer/confirm_enter.html
@@ -0,0 +1,12 @@
+{% import "bootstrap/utils.html" as utils %}
+{% extends "base_authenticated.html" %}
+{% block content %}
+    <h2>Enter Bastli</h2>
+    <p>You request entry by clicking below.</p>
+    <form action="" method="post">
+      <input type="hidden" name="action" value="enter">
+      <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
+      <input class="btn btn-primary" type="submit" value="Apply for entry now"> or 
+      <a class="btn btn-default" role="button" href="{{ url_for('bouncer.home') }}">Go back</a>
+    </form>
+{% endblock %}
diff --git a/app/templates/bouncer/confirm_leave.html b/app/templates/bouncer/confirm_leave.html
new file mode 100644
index 0000000000000000000000000000000000000000..5946c7b8d29f99d793031f6347aae290b853e4a8
--- /dev/null
+++ b/app/templates/bouncer/confirm_leave.html
@@ -0,0 +1,12 @@
+{% import "bootstrap/utils.html" as utils %}
+{% extends "base_authenticated.html" %}
+{% block content %}
+    <h2>Leave Bastli</h2>
+    <p>You confirm that you have left the workshop by clicking below.</p>
+    <form action="" method="post">
+      <input type="hidden" name="action" value="leave">
+      <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
+      <input class="btn btn-primary" type="submit" value="Leave now"> or 
+      <a class="btn btn-default" role="button" href="{{ url_for('bouncer.home') }}">Go back</a>
+    </form>
+{% endblock %}
diff --git a/app/templates/bouncer/home_authenticated.html b/app/templates/bouncer/home_authenticated.html
index a4dd68ccef2078348f4f4a60726343f01410dbfa..28b527f2cac3ea59b5707c0416bae23109859188 100644
--- a/app/templates/bouncer/home_authenticated.html
+++ b/app/templates/bouncer/home_authenticated.html
@@ -1,19 +1,29 @@
 {% import "bootstrap/utils.html" as utils %}
-{% extends "base.html" %}
-{% block body %}
-<div class="content-section">
-  <br/>
-  {{ utils.flashed_messages() }}
-  <br/>
-  <div class="center-narrow">
-    <h1>Bastli Bouncer</h1>
-    <br/>
-    <p>We currently have <span class="free_spots">{{ free_spots }} free spots</span> in our workshop.</p>
-    <p>
-      Welcome, {{ name }} ({{ email }}).
-      <a class="btn btn-default" role="button" href="{{ url_for('login.logout') }}">Logout</a>
-    </p>
-    <br/>
-  </div>
-</div>
+{% extends "base_authenticated.html" %}
+{% block content %}
+    {% if record %}
+      <div class="active_record">
+        You reported to be at Bastli.
+        <a class="btn btn-default" role="button" href="{{ url_for('bouncer.confirm_leave') }}">Leave now</a>
+      </div>
+    {% elif reservation %}
+      <div class="active_reservation">
+      You have a valid reservation expiring at {{ reservation.time_end.strftime("%H:%M") }}.
+      <a class="btn btn-default" role="button" href="{{ url_for('bouncer.confirm_enter') }}">Enter now</a>
+       or 
+       <a class="btn btn-default" role="button" href="{{ url_for('bouncer.confirm_cancel') }}">Cancel reservation</a>
+    </div>
+    {% else %}
+      <form action="" method="post">
+        <input type="hidden" name="action" value="reserve">
+        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
+        <input class="btn btn-primary" type="submit" value="Reserve a spot">
+      </form>
+       or 
+       <form action="" method="post">
+        <input type="hidden" name="action" value="enter">
+        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
+        <input class="btn btn-primary" type="submit" value="Apply for entry">
+      </form>
+    {% endif %}
 {% endblock %}
diff --git a/app/templates/login/confirm_email.html b/app/templates/login/confirm_email.html
index 0e2604d532dad3357af0c7bed805a6f0bbed13d9..29904308ee896bffb0af1f4dee694706aa57ab36 100644
--- a/app/templates/login/confirm_email.html
+++ b/app/templates/login/confirm_email.html
@@ -16,6 +16,7 @@
         <input type="hidden" name="email" value="{{ email }}">
         <input type="hidden" name="token" value="{{ token }}">
         <input type="hidden" name="action" value="confirm">
+        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
         <input class="btn btn-primary" type="submit" value="Confirm">
         <a class="btn btn-default" role="button" href="{{ url_for('bouncer.home') }}">Abort</a>
       </form>
diff --git a/app/templates/login/login.html b/app/templates/login/login.html
index 025203cd40d56255a339e96d07a4916b6662eba2..5fc08ef1a0db0806d7088bf46844134075ca8c63 100644
--- a/app/templates/login/login.html
+++ b/app/templates/login/login.html
@@ -15,6 +15,7 @@
       <input type="email" id="email" name="email" value="{{ request.form.email }}"><br/>
       <label for="name">Password:</label><br>
       <input type="password" id="password" name="password" value="{{ request.form.password }}"><br/>
+      <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
       <input class="btn btn-primary" type="submit" value="Login"> or 
       <a class="btn btn-default" role="button" href="{{ url_for('bouncer.home') }}">Go back</a>
     </form>
diff --git a/app/templates/login/register.html b/app/templates/login/register.html
index ac13ea7c94b3fd652c9a6a72d41725f3e699d9b7..d924a6f810e60a4b3a63678c19f3764793072ee5 100644
--- a/app/templates/login/register.html
+++ b/app/templates/login/register.html
@@ -19,6 +19,7 @@
       <input type="password" id="password" name="password" value="{{ request.form.password }}"><br/>
       <label for="name">Repeat Password:</label><br>
       <input type="password" id="password2" name="password2" value="{{ request.form.password2 }}"><br/>
+      <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
       <input class="btn btn-primary" type="submit" value="Register"> or 
       <a class="btn btn-default" role="button" href="{{ url_for('bouncer.home') }}">Go back</a>
     </form>
diff --git a/docker-compose.yml b/docker-compose.yml
index 7e8e628adb3733fa9cf4058041053999124d607b..1696f2a8177d7862dca9291282b6229f13bbe15c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -13,6 +13,7 @@ services:
       - MYSQL_RANDOM_ROOT_PASSWORD=yes
     volumes:
       - ./.data/:/var/lib/mysql
+      - /etc/localtime:/etc/localtime
   smtp:
     build:
       dockerfile: Dockerfile.smtp-mock
@@ -21,6 +22,8 @@ services:
     restart: always
     networks:
       - backend
+    volumes:
+      - /etc/localtime:/etc/localtime
 
 networks:
   backend:
diff --git a/instance/config.dev.py b/instance/config.dev.py
index ab0915c147a8caa89389a07eadd54385a2ba6edf..6e2b8034eba72c208d6da43e98ef266167726cf7 100644
--- a/instance/config.dev.py
+++ b/instance/config.dev.py
@@ -4,7 +4,7 @@ from datetime import timedelta
 TOTAL_SPOTS = 3
 RESERVATION_DURATION = timedelta(hours=1)
 RECORD_TIMEOUT = timedelta(hours=24)
-USER_TOKEN_TIMEOUT = timedelta(hours=12)
+USER_TOKEN_TIMEOUT = timedelta(hours=4)
 
 SERVER_NAME = 'localhost:5000'
 
diff --git a/manage.sh b/manage.sh
index 436cbcdd1a77f08dc4038ef896f0e5da0e11229b..8a09d0b23979a9950a7e0e7d7f48b9bb731950b7 100755
--- a/manage.sh
+++ b/manage.sh
@@ -11,6 +11,7 @@ BASE_DOCKER_RUN_COMMAND="${SUDO_COMMAND} docker run -it \
     --network bastli-bouncer_backend \
     -v ${PWD}:/bastlibouncer \
     -v ${PWD}/instance/config.dev.py:/bastlibouncer/instance/config.py \
+    -v /etc/localtime:/etc/localtime
     bastlibouncer-dev"
 
 case $1 in
@@ -32,7 +33,7 @@ case $1 in
                 $SUDO_COMMAND docker-compose stop
                 ;;
             *)
-                echo "Unknown sub-command for command \"db\"."
+                echo "Unknown sub-command for command \"services\"."
                 exit 1
                 ;;
         esac
diff --git a/requirements.in b/requirements.in
index 31cc083d70ae2e56fbcb4cee44b516a2cb322b73..ff5bbfac1a31e4f4a1b73d86cb738d032d8af2b9 100644
--- a/requirements.in
+++ b/requirements.in
@@ -6,6 +6,7 @@ flask-bootstrap
 flask-migrate
 flask-sqlalchemy
 Flask-Mail
+flask-wtf
 
 py3-validate-email
 
diff --git a/requirements.txt b/requirements.txt
index 4393a99fe0493e4562b9523c3aa7ddab9b60c031..c2f9e5871439e050f945a99df06c954810d040ef 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -14,12 +14,13 @@ flask-bootstrap==3.3.7.1  # via -r requirements.in
 flask-mail==0.9.1         # via -r requirements.in
 flask-migrate==2.5.3      # via -r requirements.in
 flask-sqlalchemy==2.4.3   # via -r requirements.in, flask-migrate
-flask==1.1.2              # via -r requirements.in, flask-bootstrap, flask-mail, flask-migrate, flask-sqlalchemy
+flask-wtf==0.14.3         # via -r requirements.in
+flask==1.1.2              # via -r requirements.in, flask-bootstrap, flask-mail, flask-migrate, flask-sqlalchemy, flask-wtf
 idna==2.10                # via py3-validate-email
-itsdangerous==1.1.0       # via flask
+itsdangerous==1.1.0       # via flask, flask-wtf
 jinja2==2.11.2            # via flask
 mako==1.1.3               # via alembic
-markupsafe==1.1.1         # via jinja2, mako
+markupsafe==1.1.1         # via jinja2, mako, wtforms
 py3-validate-email==0.2.9  # via -r requirements.in
 pymysql==0.9.3            # via -r requirements.in
 python-dateutil==2.8.1    # via alembic
@@ -28,3 +29,4 @@ six==1.15.0               # via python-dateutil
 sqlalchemy==1.3.18        # via alembic, flask-sqlalchemy
 visitor==0.1.3            # via flask-bootstrap
 werkzeug==1.0.1           # via flask
+wtforms==2.3.1            # via flask-wtf