diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index aaa3bd496dcb2509ee39495a062dbdd104623a02..0000000000000000000000000000000000000000
--- a/.coveragerc
+++ /dev/null
@@ -1,5 +0,0 @@
-[run]
-include = contributions/*
-omit = *migrations*, *tests*
-plugins =
-    django_coverage_plugin
diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index 8571d2eee9655c938ca0daa221dc05d030f2a76b..0000000000000000000000000000000000000000
--- a/.dockerignore
+++ /dev/null
@@ -1,62 +0,0 @@
-.*
-!.coveragerc
-!.env
-!.pylintrc
-*.pyc
-
-### OSX ###
-.DS_Store
-.AppleDouble
-.LSOverride
-
-### SublimeText ###
-# cache files for sublime text
-*.tmlanguage.cache
-*.tmPreferences.cache
-*.stTheme.cache
-
-# workspace files are user-specific
-*.sublime-workspace
-
-# project files should be checked into the repository, unless a significant
-# proportion of contributors will probably not be using SublimeText
-# *.sublime-project
-
-# sftp configuration file
-sftp-config.json
-
-# Basics
-*.py[cod]
-__pycache__
-
-# Logs
-*.log
-api/pip-log.txt
-
-# Unit test / coverage reports
-.coverage
-.tox
-nosetests.xml
-htmlcov
-
-# Translations
-*.mo
-*.pot
-
-# Pycharm
-.idea
-
-# Vim
-
-*~
-*.swp
-*.swo
-
-# npm
-front/node_modules/
-
-# Compass
-.sass-cache
-
-# virtual environments
-.env
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4a49e05740c951b4b1e88c65f61a4f579a5545c2..51cc3c3a42b5633f32b8b4064d6f8a72ed58299f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -8,15 +8,14 @@ pages:
   before_script:
     - apt-get update
     - apt-get install -y jq gettext
-    - cd front
     - yarn install
   script:
     - yarn build
-    - mv dist ../public
+    - mv dist public
   cache:
     key: front_node_modules
     paths:
-      - "front/node_modules"
+      - "node_modules"
   artifacts:
     paths:
       - public/
diff --git a/.pylintrc b/.pylintrc
deleted file mode 100644
index feecc1bfac39a8f99a1a50525efd4143ddb1492d..0000000000000000000000000000000000000000
--- a/.pylintrc
+++ /dev/null
@@ -1,14 +0,0 @@
-[MASTER]
-load-plugins=pylint_common, pylint_django
-
-[FORMAT]
-max-line-length=120
-
-[MESSAGES CONTROL]
-disable=missing-docstring,invalid-name
-
-[DESIGN]
-max-parents=13
-
-[TYPECHECK]
-generated-members=REQUEST,acl_users,aq_parent,"[a-zA-Z]+_set{1,2}",save,delete
diff --git a/front/README.md b/README.md
similarity index 100%
rename from front/README.md
rename to README.md
diff --git a/README.rst b/README.rst
deleted file mode 100644
index 5857a5ffa6c5f69b39dab9116452893c7746fe49..0000000000000000000000000000000000000000
--- a/README.rst
+++ /dev/null
@@ -1,101 +0,0 @@
-Contributions
-=============
-
-A tribute to our awesome contributors
-
-.. image:: https://img.shields.io/badge/built%20with-Cookiecutter%20Django-ff69b4.svg
-     :target: https://github.com/pydanny/cookiecutter-django/
-     :alt: Built with Cookiecutter Django
-
-
-:License: GPLv3
-
-Goals:
-
-- have a log of contributions happening in various area:
-    - Gitlab: MR, comments
-    - Weblate: translations (comments?)
-    - Financial contributions (open collective)
-    - Opened instances
-    - Other contributions: blog entries, comunication around the project, third party-project, support, whatever
-
-- store a list of tasks awaiting contributions
-- provide easy and clear instructions on how to contribute (for each type of contributions)
-
-
-- model:
-    - Contributor table: contributor id, name, links to contributions platforms, creation_date, is_visible
-    - Contribution table: id, platform id, json metadata, url, creation_date, import_date, is_visible, title, type
-    - Task table: id, type, name, url,
-
-
-Settings
---------
-
-Moved to settings_.
-
-.. _settings: http://cookiecutter-django.readthedocs.io/en/latest/settings.html
-
-Basic Commands
---------------
-
-Setting Up Your Users
-^^^^^^^^^^^^^^^^^^^^^
-
-* To create a **normal user account**, just go to Sign Up and fill out the form. Once you submit it, you'll see a "Verify Your E-mail Address" page. Go to your console to see a simulated email verification message. Copy the link into your browser. Now the user's email should be verified and ready to go.
-
-* To create an **superuser account**, use this command::
-
-    $ python manage.py createsuperuser
-
-For convenience, you can keep your normal user logged in on Chrome and your superuser logged in on Firefox (or similar), so that you can see how the site behaves for both kinds of users.
-
-Type checks
-^^^^^^^^^^^
-
-Running type checks with mypy:
-
-::
-
-  $ mypy contributions
-
-Test coverage
-^^^^^^^^^^^^^
-
-To run the tests, check your test coverage, and generate an HTML coverage report::
-
-    $ coverage run -m pytest
-    $ coverage html
-    $ open htmlcov/index.html
-
-Running tests with py.test
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-::
-
-  $ pytest
-
-Live reloading and Sass CSS compilation
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Moved to `Live reloading and SASS compilation`_.
-
-.. _`Live reloading and SASS compilation`: http://cookiecutter-django.readthedocs.io/en/latest/live-reloading-and-sass-compilation.html
-
-
-
-
-
-Deployment
-----------
-
-The following details how to deploy this application.
-
-
-
-Docker
-^^^^^^
-
-See detailed `cookiecutter-django Docker documentation`_.
-
-.. _`cookiecutter-django Docker documentation`: http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html
diff --git a/front/babel.config.js b/babel.config.js
similarity index 100%
rename from front/babel.config.js
rename to babel.config.js
diff --git a/compose/local/django/Dockerfile b/compose/local/django/Dockerfile
deleted file mode 100644
index 05e31fe37727424438f6aa685c3099e3d7bc0c90..0000000000000000000000000000000000000000
--- a/compose/local/django/Dockerfile
+++ /dev/null
@@ -1,34 +0,0 @@
-FROM python:3.6-alpine
-
-ENV PYTHONUNBUFFERED 1
-
-RUN apk update \
-  # psycopg2 dependencies
-  && apk add --virtual build-deps gcc python3-dev musl-dev \
-  && apk add postgresql-dev \
-  # Pillow dependencies
-  && apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
-  # CFFI dependencies
-  && apk add libffi-dev py-cffi \
-  # Translations dependencies
-  && apk add gettext \
-  # https://docs.djangoproject.com/en/dev/ref/django-admin/#dbshell
-  && apk add postgresql-client
-
-# Requirements are installed here to ensure they will be cached.
-COPY ./requirements/base.txt /requirements/base.txt
-RUN pip install -r /requirements/base.txt
-COPY ./requirements/local.txt /requirements/local.txt
-RUN pip install -r /requirements/local.txt
-
-COPY ./compose/production/django/entrypoint /entrypoint
-RUN sed -i 's/\r//' /entrypoint
-RUN chmod +x /entrypoint
-
-COPY ./compose/local/django/start /start
-RUN sed -i 's/\r//' /start
-RUN chmod +x /start
-
-WORKDIR /app
-
-ENTRYPOINT ["/entrypoint"]
diff --git a/compose/local/django/start b/compose/local/django/start
deleted file mode 100644
index 921604dcbaa9874ea81c258d5b8227ecfb6b1847..0000000000000000000000000000000000000000
--- a/compose/local/django/start
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-
-set -o errexit
-set -o pipefail
-set -o nounset
-
-
-python manage.py migrate
-python manage.py runserver_plus 0.0.0.0:8000
diff --git a/compose/production/caddy/Caddyfile b/compose/production/caddy/Caddyfile
deleted file mode 100644
index ec9ae277519f651a4e9698a9ae1dffb3605022ec..0000000000000000000000000000000000000000
--- a/compose/production/caddy/Caddyfile
+++ /dev/null
@@ -1,14 +0,0 @@
-www.{$DOMAIN_NAME} {
-    redir https://{$DOMAIN_NAME}
-}
-
-{$DOMAIN_NAME} {
-    proxy / django:5000 {
-        header_upstream Host {host}
-        header_upstream X-Real-IP {remote}
-        header_upstream X-Forwarded-Proto {scheme}
-    }
-    log stdout
-    errors stdout
-    gzip
-}
diff --git a/compose/production/caddy/Dockerfile b/compose/production/caddy/Dockerfile
deleted file mode 100644
index c32efb3eee82af83cea6779d0543c91fab564089..0000000000000000000000000000000000000000
--- a/compose/production/caddy/Dockerfile
+++ /dev/null
@@ -1,3 +0,0 @@
-FROM abiosoft/caddy:0.11.0
-
-COPY ./compose/production/caddy/Caddyfile /etc/Caddyfile
diff --git a/compose/production/django/Dockerfile b/compose/production/django/Dockerfile
deleted file mode 100644
index 8121ca57909608c25664c1bfde412867483640d5..0000000000000000000000000000000000000000
--- a/compose/production/django/Dockerfile
+++ /dev/null
@@ -1,40 +0,0 @@
-FROM python:3.6-alpine
-
-ENV PYTHONUNBUFFERED 1
-
-RUN apk update \
-  # psycopg2 dependencies
-  && apk add --virtual build-deps gcc python3-dev musl-dev \
-  && apk add postgresql-dev \
-  # Pillow dependencies
-  && apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
-  # CFFI dependencies
-  && apk add libffi-dev py-cffi
-
-RUN addgroup -S django \
-    && adduser -S -G django django
-
-# Requirements are installed here to ensure they will be cached.
-COPY ./requirements /requirements
-RUN pip install --no-cache-dir -r /requirements/production.txt \
-    && rm -rf /requirements
-
-COPY ./compose/production/django/entrypoint /entrypoint
-RUN sed -i 's/\r//' /entrypoint
-RUN chmod +x /entrypoint
-RUN chown django /entrypoint
-
-COPY ./compose/production/django/start /start
-RUN sed -i 's/\r//' /start
-RUN chmod +x /start
-RUN chown django /start
-
-COPY . /app
-
-RUN chown -R django /app
-
-USER django
-
-WORKDIR /app
-
-ENTRYPOINT ["/entrypoint"]
diff --git a/compose/production/django/entrypoint b/compose/production/django/entrypoint
deleted file mode 100644
index 4845e343bd12ee1864450cb97ad800b54dcf58c5..0000000000000000000000000000000000000000
--- a/compose/production/django/entrypoint
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/sh
-
-set -o errexit
-set -o pipefail
-set -o nounset
-
-
-# N.B. If only .env files supported variable expansion...
-export CELERY_BROKER_URL="${REDIS_URL}"
-
-if [ -z "${POSTGRES_USER}" ]; then
-    base_postgres_image_default_user='postgres'
-    export POSTGRES_USER="${base_postgres_image_default_user}"
-fi
-export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}"
-
-postgres_ready() {
-python << END
-import sys
-
-import psycopg2
-
-try:
-    psycopg2.connect(
-        dbname="${POSTGRES_DB}",
-        user="${POSTGRES_USER}",
-        password="${POSTGRES_PASSWORD}",
-        host="${POSTGRES_HOST}",
-        port="${POSTGRES_PORT}",
-    )
-except psycopg2.OperationalError:
-    sys.exit(-1)
-sys.exit(0)
-
-END
-}
-until postgres_ready; do
-  >&2 echo 'Waiting for PostgreSQL to become available...'
-  sleep 1
-done
->&2 echo 'PostgreSQL is available'
-
-exec "$@"
diff --git a/compose/production/django/start b/compose/production/django/start
deleted file mode 100644
index 0ad39dfaee84999409defd055b6e62860d7f77d2..0000000000000000000000000000000000000000
--- a/compose/production/django/start
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-
-set -o errexit
-set -o pipefail
-set -o nounset
-
-
-python /app/manage.py collectstatic --noinput
-/usr/local/bin/gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app
diff --git a/compose/production/postgres/Dockerfile b/compose/production/postgres/Dockerfile
deleted file mode 100644
index 4960442714d972840ca2ef50da88735104cafce0..0000000000000000000000000000000000000000
--- a/compose/production/postgres/Dockerfile
+++ /dev/null
@@ -1,6 +0,0 @@
-FROM postgres:10.4
-
-COPY ./compose/production/postgres/maintenance /usr/local/bin/maintenance
-RUN chmod +x /usr/local/bin/maintenance/*
-RUN mv /usr/local/bin/maintenance/* /usr/local/bin \
-    && rmdir /usr/local/bin/maintenance
diff --git a/compose/production/postgres/maintenance/_sourced/constants.sh b/compose/production/postgres/maintenance/_sourced/constants.sh
deleted file mode 100644
index 6ca4f0ca9c64f449bf3774f3e3d90a274f2261d0..0000000000000000000000000000000000000000
--- a/compose/production/postgres/maintenance/_sourced/constants.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-
-
-BACKUP_DIR_PATH='/backups'
-BACKUP_FILE_PREFIX='backup'
diff --git a/compose/production/postgres/maintenance/_sourced/countdown.sh b/compose/production/postgres/maintenance/_sourced/countdown.sh
deleted file mode 100644
index e6cbfb6ffc2996031dae959b1ebf3e1f71b77551..0000000000000000000000000000000000000000
--- a/compose/production/postgres/maintenance/_sourced/countdown.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-
-countdown() {
-    declare desc="A simple countdown. Source: https://superuser.com/a/611582"
-    local seconds="${1}"
-    local d=$(($(date +%s) + "${seconds}"))
-    while [ "$d" -ge `date +%s` ]; do
-        echo -ne "$(date -u --date @$(($d - `date +%s`)) +%H:%M:%S)\r";
-        sleep 0.1
-    done
-}
diff --git a/compose/production/postgres/maintenance/_sourced/messages.sh b/compose/production/postgres/maintenance/_sourced/messages.sh
deleted file mode 100644
index f6be756e97d36815e2f7d606438375c14371bfc5..0000000000000000000000000000000000000000
--- a/compose/production/postgres/maintenance/_sourced/messages.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-
-
-message_newline() {
-    echo
-}
-
-message_debug()
-{
-    echo -e "DEBUG: ${@}"
-}
-
-message_welcome()
-{
-    echo -e "\e[1m${@}\e[0m"
-}
-
-message_warning()
-{
-    echo -e "\e[33mWARNING\e[0m: ${@}"
-}
-
-message_error()
-{
-    echo -e "\e[31mERROR\e[0m: ${@}"
-}
-
-message_info()
-{
-    echo -e "\e[37mINFO\e[0m: ${@}"
-}
-
-message_suggestion()
-{
-    echo -e "\e[33mSUGGESTION\e[0m: ${@}"
-}
-
-message_success()
-{
-    echo -e "\e[32mSUCCESS\e[0m: ${@}"
-}
diff --git a/compose/production/postgres/maintenance/_sourced/yes_no.sh b/compose/production/postgres/maintenance/_sourced/yes_no.sh
deleted file mode 100644
index fd9cae161435e5292a26785ccc7a09551801b6de..0000000000000000000000000000000000000000
--- a/compose/production/postgres/maintenance/_sourced/yes_no.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-
-
-yes_no() {
-    declare desc="Prompt for confirmation. \$\"\{1\}\": confirmation message."
-    local arg1="${1}"
-
-    local response=
-    read -r -p "${arg1} (y/[n])? " response
-    if [[ "${response}" =~ ^[Yy]$ ]]
-    then
-        exit 0
-    else
-        exit 1
-    fi
-}
diff --git a/compose/production/postgres/maintenance/backup b/compose/production/postgres/maintenance/backup
deleted file mode 100644
index ee0c9d63cd59a8502e622444c4191e11355f3cbb..0000000000000000000000000000000000000000
--- a/compose/production/postgres/maintenance/backup
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env bash
-
-
-### Create a database backup.
-###
-### Usage:
-###     $ docker-compose -f <environment>.yml (exec |run --rm) postgres backup
-
-
-set -o errexit
-set -o pipefail
-set -o nounset
-
-
-working_dir="$(dirname ${0})"
-source "${working_dir}/_sourced/constants.sh"
-source "${working_dir}/_sourced/messages.sh"
-
-
-message_welcome "Backing up the '${POSTGRES_DB}' database..."
-
-
-if [[ "${POSTGRES_USER}" == "postgres" ]]; then
-    message_error "Backing up as 'postgres' user is not supported. Assign 'POSTGRES_USER' env with another one and try again."
-    exit 1
-fi
-
-export PGHOST="${POSTGRES_HOST}"
-export PGPORT="${POSTGRES_PORT}"
-export PGUSER="${POSTGRES_USER}"
-export PGPASSWORD="${POSTGRES_PASSWORD}"
-export PGDATABASE="${POSTGRES_DB}"
-
-backup_filename="${BACKUP_FILE_PREFIX}_$(date +'%Y_%m_%dT%H_%M_%S').sql.gz"
-pg_dump | gzip > "${BACKUP_DIR_PATH}/${backup_filename}"
-
-
-message_success "'${POSTGRES_DB}' database backup '${backup_filename}' has been created and placed in '${BACKUP_DIR_PATH}'."
diff --git a/compose/production/postgres/maintenance/backups b/compose/production/postgres/maintenance/backups
deleted file mode 100644
index 0484ccff50d7cd942d8793e94530e37ebf102344..0000000000000000000000000000000000000000
--- a/compose/production/postgres/maintenance/backups
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-
-### View backups.
-###
-### Usage:
-###     $ docker-compose -f <environment>.yml (exec |run --rm) postgres backups
-
-
-set -o errexit
-set -o pipefail
-set -o nounset
-
-
-working_dir="$(dirname ${0})"
-source "${working_dir}/_sourced/constants.sh"
-source "${working_dir}/_sourced/messages.sh"
-
-
-message_welcome "These are the backups you have got:"
-
-ls -lht "${BACKUP_DIR_PATH}"
diff --git a/compose/production/postgres/maintenance/restore b/compose/production/postgres/maintenance/restore
deleted file mode 100644
index 9661ca7f1ac38e4b061bc4e1e70b8b5be7aca8b5..0000000000000000000000000000000000000000
--- a/compose/production/postgres/maintenance/restore
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env bash
-
-
-### Restore database from a backup.
-###
-### Parameters:
-###     <1> filename of an existing backup.
-###
-### Usage:
-###     $ docker-compose -f <environment>.yml (exec |run --rm) postgres restore <1>
-
-
-set -o errexit
-set -o pipefail
-set -o nounset
-
-
-working_dir="$(dirname ${0})"
-source "${working_dir}/_sourced/constants.sh"
-source "${working_dir}/_sourced/messages.sh"
-
-
-if [[ -z ${1+x} ]]; then
-    message_error "Backup filename is not specified yet it is a required parameter. Make sure you provide one and try again."
-    exit 1
-fi
-backup_filename="${BACKUP_DIR_PATH}/${1}"
-if [[ ! -f "${backup_filename}" ]]; then
-    message_error "No backup with the specified filename found. Check out the 'backups' maintenance script output to see if there is one and try again."
-    exit 1
-fi
-
-message_welcome "Restoring the '${POSTGRES_DB}' database from the '${backup_filename}' backup..."
-
-if [[ "${POSTGRES_USER}" == "postgres" ]]; then
-    message_error "Restoring as 'postgres' user is not supported. Assign 'POSTGRES_USER' env with another one and try again."
-    exit 1
-fi
-
-export PGHOST="${POSTGRES_HOST}"
-export PGPORT="${POSTGRES_PORT}"
-export PGUSER="${POSTGRES_USER}"
-export PGPASSWORD="${POSTGRES_PASSWORD}"
-export PGDATABASE="${POSTGRES_DB}"
-
-message_info "Dropping the database..."
-dropdb "${PGDATABASE}"
-
-message_info "Creating a new database..."
-createdb --owner="${POSTGRES_USER}"
-
-message_info "Applying the backup to the new database..."
-gunzip -c "${backup_filename}" | psql "${POSTGRES_DB}"
-
-message_success "The '${POSTGRES_DB}' database has been restored from the '${backup_filename}' backup."
diff --git a/config/__init__.py b/config/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/config/settings/__init__.py b/config/settings/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/config/settings/base.py b/config/settings/base.py
deleted file mode 100644
index dad99ae6413498b290cc31c9ac53460c5b590950..0000000000000000000000000000000000000000
--- a/config/settings/base.py
+++ /dev/null
@@ -1,243 +0,0 @@
-"""
-Base settings to build other settings files upon.
-"""
-
-import environ
-
-ROOT_DIR = (
-    environ.Path(__file__) - 3
-)  # (contributions/config/settings/base.py - 3 = contributions/)
-APPS_DIR = ROOT_DIR.path("contributions")
-
-env = environ.Env()
-
-READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=False)
-if READ_DOT_ENV_FILE:
-    # OS environment variables take precedence over variables from .env
-    env.read_env(str(ROOT_DIR.path(".env")))
-
-
-SECRET_KEY = env("DJANGO_SECRET_KEY")
-ALLOWED_HOSTS = env.list(
-    "DJANGO_ALLOWED_HOSTS", default=["contributions.funkwhale.audio"]
-)
-
-
-# GENERAL
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#debug
-DEBUG = env.bool("DJANGO_DEBUG", False)
-# Local time zone. Choices are
-# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
-# though not all of them may be available with every OS.
-# In Windows, this must be set to your system time zone.
-TIME_ZONE = "UTC"
-# https://docs.djangoproject.com/en/dev/ref/settings/#language-code
-LANGUAGE_CODE = "en-us"
-# https://docs.djangoproject.com/en/dev/ref/settings/#site-id
-SITE_ID = 1
-# https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
-USE_I18N = True
-# https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n
-USE_L10N = True
-# https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
-USE_TZ = True
-
-# DATABASES
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#databases
-DATABASES = {"default": env.db("DATABASE_URL")}
-DATABASES["default"]["ATOMIC_REQUESTS"] = True
-DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60)  # noqa F405
-
-
-CACHES = {
-    "default": {
-        "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
-        "LOCATION": "",
-    }
-}
-
-
-# URLS
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf
-ROOT_URLCONF = "config.urls"
-# https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
-WSGI_APPLICATION = "config.wsgi.application"
-
-# APPS
-# ------------------------------------------------------------------------------
-DJANGO_APPS = [
-    "django.contrib.auth",
-    "django.contrib.contenttypes",
-    "django.contrib.sessions",
-    "django.contrib.sites",
-    "django.contrib.messages",
-    "django.contrib.staticfiles",
-    # 'django.contrib.humanize', # Handy template tags
-    "django.contrib.admin",
-]
-THIRD_PARTY_APPS = [
-    "allauth",
-    "allauth.account",
-    "allauth.socialaccount",
-    "rest_framework",
-    "corsheaders",
-    "django_filters",
-]
-LOCAL_APPS = [
-    "contributions.users.apps.UsersAppConfig",
-    # Your stuff: custom apps go here
-    "contributions.core",
-]
-# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
-INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
-
-
-# AUTHENTICATION
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#authentication-backends
-AUTHENTICATION_BACKENDS = [
-    "django.contrib.auth.backends.ModelBackend",
-    "allauth.account.auth_backends.AuthenticationBackend",
-]
-# https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model
-AUTH_USER_MODEL = "users.User"
-# https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url
-LOGIN_REDIRECT_URL = "users:redirect"
-# https://docs.djangoproject.com/en/dev/ref/settings/#login-url
-LOGIN_URL = "account_login"
-
-# PASSWORDS
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers
-PASSWORD_HASHERS = [
-    "django.contrib.auth.hashers.PBKDF2PasswordHasher",
-    "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
-    "django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
-    "django.contrib.auth.hashers.BCryptPasswordHasher",
-]
-# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators
-AUTH_PASSWORD_VALIDATORS = [
-    {
-        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
-    },
-    {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
-    {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
-    {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
-]
-
-# MIDDLEWARE
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#middleware
-MIDDLEWARE = [
-    "django.middleware.security.SecurityMiddleware",
-    "django.contrib.sessions.middleware.SessionMiddleware",
-    "django.middleware.common.CommonMiddleware",
-    "django.middleware.csrf.CsrfViewMiddleware",
-    "django.contrib.auth.middleware.AuthenticationMiddleware",
-    "django.contrib.messages.middleware.MessageMiddleware",
-    "django.middleware.clickjacking.XFrameOptionsMiddleware",
-    "corsheaders.middleware.CorsMiddleware",
-    "django.middleware.common.CommonMiddleware",
-]
-
-# STATIC
-# ------------------------------------------------------------------------------
-STATIC_URL = env("STATIC_URL", default="/static/")
-STATIC_ROOT = env("STATIC_ROOT", default=str(ROOT_DIR("staticfiles")))
-
-# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
-STATICFILES_DIRS = []
-# https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders
-STATICFILES_FINDERS = [
-    "django.contrib.staticfiles.finders.FileSystemFinder",
-    "django.contrib.staticfiles.finders.AppDirectoriesFinder",
-]
-
-# MEDIA
-# ------------------------------------------------------------------------------
-MEDIA_URL = env("MEDIA_URL", default="/media/")
-MEDIA_ROOT = env("MEDIA_ROOT", default=str(APPS_DIR("media")))
-
-# TEMPLATES
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#templates
-TEMPLATES = [
-    {
-        # https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND
-        "BACKEND": "django.template.backends.django.DjangoTemplates",
-        # https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
-        "DIRS": [str(APPS_DIR.path("templates"))],
-        "OPTIONS": {
-            # https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
-            "debug": DEBUG,
-            # https://docs.djangoproject.com/en/dev/ref/settings/#template-loaders
-            # https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types
-            "loaders": [
-                "django.template.loaders.filesystem.Loader",
-                "django.template.loaders.app_directories.Loader",
-            ],
-            # https://docs.djangoproject.com/en/dev/ref/settings/#template-context-processors
-            "context_processors": [
-                "django.template.context_processors.debug",
-                "django.template.context_processors.request",
-                "django.contrib.auth.context_processors.auth",
-                "django.template.context_processors.i18n",
-                "django.template.context_processors.media",
-                "django.template.context_processors.static",
-                "django.template.context_processors.tz",
-                "django.contrib.messages.context_processors.messages",
-            ],
-        },
-    }
-]
-TEMPLATES[0]["OPTIONS"]["debug"] = DEBUG  # noqa F405
-
-# FIXTURES
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#fixture-dirs
-FIXTURE_DIRS = (str(APPS_DIR.path("fixtures")),)
-
-# EMAIL
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
-EMAIL_BACKEND = env(
-    "DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend"
-)
-DEFAULT_FROM_EMAIL = env(
-    "DJANGO_DEFAULT_FROM_EMAIL",
-    default="Contributions <noreply@contributions.funkwhale.audio>",
-)
-SERVER_EMAIL = env("DJANGO_SERVER_EMAIL", default=DEFAULT_FROM_EMAIL)
-# https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix
-EMAIL_SUBJECT_PREFIX = env("DJANGO_EMAIL_SUBJECT_PREFIX", default="[Contributions]")
-
-# https://docs.djangoproject.com
-# ADMIN
-# ------------------------------------------------------------------------------
-# Django Admin URL.
-ADMIN_URL = env("DJANGO_ADMIN_URL", default="admin/")
-
-# django-allauth
-# ------------------------------------------------------------------------------
-ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", False)
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
-ACCOUNT_AUTHENTICATION_METHOD = "username"
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
-ACCOUNT_EMAIL_REQUIRED = True
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
-ACCOUNT_EMAIL_VERIFICATION = "mandatory"
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
-ACCOUNT_ADAPTER = "contributions.users.adapters.AccountAdapter"
-# https://django-allauth.readthedocs.io/en/latest/configuration.html
-SOCIALACCOUNT_ADAPTER = "contributions.users.adapters.SocialAccountAdapter"
-
-
-REST_FRAMEWORK = {
-    "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
-    "PAGE_SIZE": 100,
-}
-
-CORS_ORIGIN_ALLOW_ALL = True
diff --git a/config/settings/local.py b/config/settings/local.py
deleted file mode 100644
index 0b28e05c1d715e734986bcad7cc36e6fa07b06eb..0000000000000000000000000000000000000000
--- a/config/settings/local.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from .base import *  # noqa
-from .base import env
-
-INSTALLED_APPS += ['debug_toolbar']  # noqa F405
-MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']  # noqa F405
-
-# https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config
-DEBUG_TOOLBAR_CONFIG = {
-    'DISABLE_PANELS': [
-        'debug_toolbar.panels.redirects.RedirectsPanel',
-    ],
-    'SHOW_TEMPLATE_CONTEXT': True,
-}
-# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips
-INTERNAL_IPS = ['127.0.0.1', '10.0.2.2']
-if env('USE_DOCKER') == 'yes':
-    import socket
-    hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
-    INTERNAL_IPS += [ip[:-1] + '1' for ip in ips]
diff --git a/config/settings/production.py b/config/settings/production.py
deleted file mode 100644
index 0e1ebeac78a469a5fd6c20f85626209f7443186f..0000000000000000000000000000000000000000
--- a/config/settings/production.py
+++ /dev/null
@@ -1,100 +0,0 @@
-from .base import *  # noqa
-from .base import env
-
-
-# # CACHES
-# # ------------------------------------------------------------------------------
-# CACHES = {
-#     'default': {
-#         'BACKEND': 'django_redis.cache.RedisCache',
-#         'LOCATION': env('REDIS_URL'),
-#         'OPTIONS': {
-#             'CLIENT_CLASS': 'django_redis.client.DefaultClient',
-#             # Mimicing memcache behavior.
-#             # http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior
-#             'IGNORE_EXCEPTIONS': True,
-#         }
-#     }
-# }
-
-# SECURITY
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header
-SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
-# https://docs.djangoproject.com/en/dev/ref/settings/#secure-ssl-redirect
-SECURE_SSL_REDIRECT = env.bool('DJANGO_SECURE_SSL_REDIRECT', default=True)
-# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-secure
-SESSION_COOKIE_SECURE = True
-# https://docs.djangoproject.com/en/dev/ref/settings/#session-cookie-httponly
-SESSION_COOKIE_HTTPONLY = True
-# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-secure
-CSRF_COOKIE_SECURE = True
-# https://docs.djangoproject.com/en/dev/ref/settings/#csrf-cookie-httponly
-CSRF_COOKIE_HTTPONLY = True
-# https://docs.djangoproject.com/en/dev/topics/security/#ssl-https
-# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-seconds
-# TODO: set this to 60 seconds first and then to 518400 once you prove the former works
-SECURE_HSTS_SECONDS = 60
-# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains
-SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool('DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS', default=True)
-# https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload
-SECURE_HSTS_PRELOAD = env.bool('DJANGO_SECURE_HSTS_PRELOAD', default=True)
-# https://docs.djangoproject.com/en/dev/ref/middleware/#x-content-type-options-nosniff
-SECURE_CONTENT_TYPE_NOSNIFF = env.bool('DJANGO_SECURE_CONTENT_TYPE_NOSNIFF', default=True)
-# https://docs.djangoproject.com/en/dev/ref/settings/#secure-browser-xss-filter
-SECURE_BROWSER_XSS_FILTER = True
-# https://docs.djangoproject.com/en/dev/ref/settings/#x-frame-options
-X_FRAME_OPTIONS = 'DENY'
-
-INSTALLED_APPS += ['gunicorn']  # noqa F405
-# LOGGING
-# ------------------------------------------------------------------------------
-# See: https://docs.djangoproject.com/en/dev/ref/settings/#logging
-# A sample logging configuration. The only tangible logging
-# performed by this configuration is to send an email to
-# the site admins on every HTTP 500 error when DEBUG=False.
-# See https://docs.djangoproject.com/en/dev/topics/logging for
-# more details on how to customize your logging configuration.
-LOGGING = {
-    'version': 1,
-    'disable_existing_loggers': False,
-    'filters': {
-        'require_debug_false': {
-            '()': 'django.utils.log.RequireDebugFalse'
-        }
-    },
-    'formatters': {
-        'verbose': {
-            'format': '%(levelname)s %(asctime)s %(module)s '
-                      '%(process)d %(thread)d %(message)s'
-        },
-    },
-    'handlers': {
-        'mail_admins': {
-            'level': 'ERROR',
-            'filters': ['require_debug_false'],
-            'class': 'django.utils.log.AdminEmailHandler'
-        },
-        'console': {
-            'level': 'DEBUG',
-            'class': 'logging.StreamHandler',
-            'formatter': 'verbose',
-        },
-    },
-    'loggers': {
-        'django.request': {
-            'handlers': ['mail_admins'],
-            'level': 'ERROR',
-            'propagate': True
-        },
-        'django.security.DisallowedHost': {
-            'level': 'ERROR',
-            'handlers': ['console', 'mail_admins'],
-            'propagate': True
-        }
-    }
-}
-
-
-# Your stuff...
-# ------------------------------------------------------------------------------
diff --git a/config/settings/test.py b/config/settings/test.py
deleted file mode 100644
index 9c3ece525044c35224ffd9817cc77b5b8a80121d..0000000000000000000000000000000000000000
--- a/config/settings/test.py
+++ /dev/null
@@ -1,22 +0,0 @@
-"""
-With these settings, tests run faster.
-"""
-
-from .base import *  # noqa
-from .base import env
-
-# GENERAL
-# ------------------------------------------------------------------------------
-# https://docs.djangoproject.com/en/dev/ref/settings/#debug
-DEBUG = False
-SECRET_KEY = env("DJANGO_SECRET_KEY", default="JCjy4ci7JJatiu7u3z7QIgiQBjktoZOHu9ZllKzRpf6OsenJus0uvlPNq8qxXxkx")
-CACHES = {
-    "default": {
-        "BACKEND": "django.core.cache.backends.locmem.LocMemCache", "LOCATION": ""
-    }
-}
-PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
-
-EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
-EMAIL_HOST = "localhost"
-EMAIL_PORT = 1025
diff --git a/config/urls.py b/config/urls.py
deleted file mode 100644
index d65eb38cc4ef370082b9518d0a1f0b54c6e7d62c..0000000000000000000000000000000000000000
--- a/config/urls.py
+++ /dev/null
@@ -1,45 +0,0 @@
-from django.conf import settings
-from django.urls import include, path
-from django.conf.urls.static import static
-from django.contrib import admin
-from django.views.generic import TemplateView
-from django.views import defaults as default_views
-
-from contributions.core import urls
-
-
-urlpatterns = [
-    path(settings.ADMIN_URL, admin.site.urls),
-    path(
-        "api/",
-        include(
-            ("contributions.core.urls", "contributions"), namespace="contributions"
-        ),
-    ),
-] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
-
-if settings.DEBUG:
-    # This allows the error pages to be debugged during development, just visit
-    # these url in browser to see how these error pages look like.
-    urlpatterns += [
-        path(
-            "400/",
-            default_views.bad_request,
-            kwargs={"exception": Exception("Bad Request!")},
-        ),
-        path(
-            "403/",
-            default_views.permission_denied,
-            kwargs={"exception": Exception("Permission Denied")},
-        ),
-        path(
-            "404/",
-            default_views.page_not_found,
-            kwargs={"exception": Exception("Page not Found")},
-        ),
-        path("500/", default_views.server_error),
-    ]
-    if "debug_toolbar" in settings.INSTALLED_APPS:
-        import debug_toolbar
-
-        urlpatterns = [path("__debug__/", include(debug_toolbar.urls))] + urlpatterns
diff --git a/config/wsgi.py b/config/wsgi.py
deleted file mode 100644
index 0c4e27a1b99848d327017b407dcbbb0c473edb67..0000000000000000000000000000000000000000
--- a/config/wsgi.py
+++ /dev/null
@@ -1,40 +0,0 @@
-"""
-WSGI config for Contributions project.
-
-This module contains the WSGI application used by Django's development server
-and any production WSGI deployments. It should expose a module-level variable
-named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
-this application via the ``WSGI_APPLICATION`` setting.
-
-Usually you will have the standard Django WSGI application here, but it also
-might make sense to replace the whole Django WSGI application with a custom one
-that later delegates to the Django one. For example, you could introduce WSGI
-middleware here, or combine a Django application with an application of another
-framework.
-
-"""
-import os
-import sys
-
-from django.core.wsgi import get_wsgi_application
-
-# This allows easy placement of apps within the interior
-# contributions directory.
-app_path = os.path.abspath(os.path.join(
-    os.path.dirname(os.path.abspath(__file__)), os.pardir))
-sys.path.append(os.path.join(app_path, 'contributions'))
-
-# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
-# if running multiple sites in the same mod_wsgi process. To fix this, use
-# mod_wsgi daemon mode with each site in its own daemon process, or use
-# os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.production"
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
-
-# This application object is used by any WSGI server configured to use this
-# file. This includes Django's development server, if the WSGI_APPLICATION
-# setting points here.
-application = get_wsgi_application()
-
-# Apply WSGI middleware here.
-# from helloworld.wsgi import HelloWorldApplication
-# application = HelloWorldApplication(application)
diff --git a/contributions/__init__.py b/contributions/__init__.py
deleted file mode 100644
index e1d861523a5bec6ae939575e8e4c1dfd758b2d69..0000000000000000000000000000000000000000
--- a/contributions/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-__version__ = "0.1.0"
-__version_info__ = tuple(
-    [
-        int(num) if num.isdigit() else num
-        for num in __version__.replace("-", ".", 1).split(".")
-    ]
-)
diff --git a/contributions/core/__init__.py b/contributions/core/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/contributions/core/admin.py b/contributions/core/admin.py
deleted file mode 100644
index 224ca306530f7399329bd6f186f7fd84abc9d23b..0000000000000000000000000000000000000000
--- a/contributions/core/admin.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from django.contrib import admin
-
-from . import models
-
-
-@admin.register(models.Contributor)
-class ContributorAdmin(admin.ModelAdmin):
-    list_display = ["username", "name", "creation_date"]
-    search_fields = ["username", "name"]
-
-
-@admin.register(models.Contribution)
-class ContributionAdmin(admin.ModelAdmin):
-    list_display = [
-        "contributor",
-        "summary",
-        "creation_date",
-        "import_date",
-        "type",
-        "external_id",
-    ]
-    search_fields = [
-        "contributor__username",
-        "contributor__name",
-        "summary",
-        "external_id",
-    ]
-
-    list_filter = ["contributor", "type"]
-
-    list_select_related = ["contributor"]
diff --git a/contributions/core/filters.py b/contributions/core/filters.py
deleted file mode 100644
index 88f6fae114f0fee60693613eb0adb2a0ce08f8a1..0000000000000000000000000000000000000000
--- a/contributions/core/filters.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from django_filters import rest_framework as filters
-
-from . import models
-
-
-class ContributionFilter(filters.FilterSet):
-    class Meta:
-        model = models.Contribution
-        fields = ["type", "contributor"]
diff --git a/contributions/core/migrations/0001_initial.py b/contributions/core/migrations/0001_initial.py
deleted file mode 100644
index 25745296aa2852b9368a01502cbaaa1a9f69899a..0000000000000000000000000000000000000000
--- a/contributions/core/migrations/0001_initial.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Generated by Django 2.1.2 on 2018-10-06 15:48
-
-import django.contrib.postgres.fields.jsonb
-from django.db import migrations, models
-import django.db.models.deletion
-import django.utils.timezone
-
-
-class Migration(migrations.Migration):
-
-    initial = True
-
-    dependencies = [
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='Contribution',
-            fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('summary', models.CharField(max_length=500)),
-                ('type', models.CharField(choices=[('dev', 'Development'), ('i18n', 'Translations'), ('network', 'Network'), ('donation', 'Donations'), ('communication', 'Communication'), ('other', 'Other')], max_length=50)),
-                ('creation_date', models.DateTimeField(default=django.utils.timezone.now)),
-                ('import_date', models.DateTimeField(default=django.utils.timezone.now)),
-                ('is_visible', models.BooleanField(default=True)),
-                ('external_id', models.CharField(max_length=250, unique=True)),
-                ('url', models.URLField()),
-                ('metadata', django.contrib.postgres.fields.jsonb.JSONField()),
-            ],
-        ),
-        migrations.CreateModel(
-            name='Contributor',
-            fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('username', models.CharField(max_length=200, unique=True)),
-                ('name', models.CharField(max_length=200)),
-                ('creation_date', models.DateTimeField(default=django.utils.timezone.now)),
-                ('is_visible', models.BooleanField(default=True)),
-                ('metadata', django.contrib.postgres.fields.jsonb.JSONField()),
-            ],
-        ),
-        migrations.AddField(
-            model_name='contribution',
-            name='contributor',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contributions', to='core.Contributor'),
-        ),
-    ]
diff --git a/contributions/core/migrations/0002_auto_20181018_1941.py b/contributions/core/migrations/0002_auto_20181018_1941.py
deleted file mode 100644
index 7cc3d10f85a4c1f240c92706a833383161576b39..0000000000000000000000000000000000000000
--- a/contributions/core/migrations/0002_auto_20181018_1941.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Generated by Django 2.1.2 on 2018-10-18 19:41
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('core', '0001_initial'),
-    ]
-
-    operations = [
-        migrations.AlterModelOptions(
-            name='contribution',
-            options={'ordering': ('-creation_date',)},
-        ),
-        migrations.AlterModelOptions(
-            name='contributor',
-            options={'ordering': ('-creation_date',)},
-        ),
-        migrations.AlterField(
-            model_name='contribution',
-            name='type',
-            field=models.CharField(choices=[('dev', 'Development'), ('dev:issue', 'Development/Issue'), ('i18n', 'Translations'), ('network', 'Network'), ('donation', 'Donations'), ('communication', 'Communication'), ('other', 'Other')], max_length=50),
-        ),
-        migrations.AlterField(
-            model_name='contribution',
-            name='url',
-            field=models.URLField(null=True),
-        ),
-    ]
diff --git a/contributions/core/migrations/__init__.py b/contributions/core/migrations/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/contributions/core/models.py b/contributions/core/models.py
deleted file mode 100644
index 1d3af48a55fbe6d4403b9ae7c56372694654c168..0000000000000000000000000000000000000000
--- a/contributions/core/models.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from django.contrib.postgres.fields import JSONField
-from django.db import models
-from django.utils import timezone
-
-
-class Contributor(models.Model):
-    username = models.CharField(max_length=200, unique=True)
-    name = models.CharField(max_length=200)
-    creation_date = models.DateTimeField(default=timezone.now)
-    is_visible = models.BooleanField(default=True)
-    metadata = JSONField()
-
-    class Meta:
-        ordering = ("-creation_date",)
-
-    def __str__(self):
-        return self.username
-
-    @property
-    def avatar_url(self):
-        paths = [("gitlab", "avatar_url"), ("opencollective", "image")]
-        for p, a in paths:
-            try:
-                return self.metadata[p][a]
-            except KeyError:
-                continue
-
-
-CONTRIBUTION_TYPES = [
-    ("dev", "Development"),
-    ("dev:issue", "Development/Issue"),
-    ("i18n", "Translations"),
-    ("network", "Network"),
-    ("donation", "Donations"),
-    ("communication", "Communication"),
-    ("other", "Other"),
-]
-
-
-class Contribution(models.Model):
-    contributor = models.ForeignKey(
-        Contributor, related_name="contributions", on_delete=models.CASCADE
-    )
-    summary = models.CharField(max_length=500)
-    type = models.CharField(max_length=50, choices=CONTRIBUTION_TYPES)
-    creation_date = models.DateTimeField(default=timezone.now)
-    import_date = models.DateTimeField(default=timezone.now)
-    is_visible = models.BooleanField(default=True)
-    external_id = models.CharField(max_length=250, unique=True)
-    url = models.URLField(null=True)
-    metadata = JSONField()
-
-    class Meta:
-        ordering = ("-creation_date",)
diff --git a/contributions/core/serializers.py b/contributions/core/serializers.py
deleted file mode 100644
index 658b7b64e2be4f5ce1cb190764886b8522a2ac05..0000000000000000000000000000000000000000
--- a/contributions/core/serializers.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from rest_framework import serializers
-
-from . import models
-
-
-class ContributorSerizalizer(serializers.ModelSerializer):
-    class Meta:
-        model = models.Contributor
-        fields = ["id", "name", "username", "metadata", "avatar_url"]
-
-
-class ContributionSerializer(serializers.ModelSerializer):
-    contributor = ContributorSerizalizer()
-
-    class Meta:
-        model = models.Contribution
-        fields = [
-            "id",
-            "metadata",
-            "contributor",
-            "summary",
-            "creation_date",
-            "import_date",
-            "type",
-            "external_id",
-            "url",
-        ]
diff --git a/contributions/core/urls.py b/contributions/core/urls.py
deleted file mode 100644
index 684f20c448ef53503922539419a2ebabff4ca2ce..0000000000000000000000000000000000000000
--- a/contributions/core/urls.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from rest_framework import routers
-
-from . import views
-
-router = routers.SimpleRouter()
-router.register(r"contributions", views.ContributionViewSet, "contributions")
-
-urlpatterns = router.urls
diff --git a/contributions/core/views.py b/contributions/core/views.py
deleted file mode 100644
index 73930a5ce1cc5599afeca17016f9927faf3ca895..0000000000000000000000000000000000000000
--- a/contributions/core/views.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from rest_framework import mixins, response, viewsets
-from rest_framework.decorators import action
-
-from django.db.models import Count
-from django_filters import rest_framework as rest_framework_filters
-
-from . import filters, models, serializers
-
-
-def get_stats(queryset):
-    by_types = (
-        models.Contribution.objects.all()
-        .values("type")
-        .annotate(total=Count("type"))
-        .order_by("total")
-    )
-    stats = {"types": {d["type"]: d["total"] for d in by_types}}
-
-    return stats
-
-
-class ContributionViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
-
-    # filter_class = filters.TrackFavoriteFilter
-    serializer_class = serializers.ContributionSerializer
-    queryset = (
-        models.Contribution.objects.filter(is_visible=True)
-        .order_by("-creation_date")
-        .select_related("contributor")
-    )
-    permission_classes = []
-    authentication_classes = []
-    filter_backends = (rest_framework_filters.DjangoFilterBackend,)
-    filterset_class = filters.ContributionFilter
-
-    @action(detail=False, methods=["get"])
-    def stats(self, request, *args, **kwargs):
-        stats = get_stats(self.get_queryset())
-        return response.Response(stats)
diff --git a/contributions/sources/gitlab.py b/contributions/sources/gitlab.py
deleted file mode 100644
index ff56b82d5fc62bd972386923ee051bc373ea1ae2..0000000000000000000000000000000000000000
--- a/contributions/sources/gitlab.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import requests
-import pendulum
-import urllib.parse
-
-from django.utils import timezone
-
-from contributions.core import models as core_models
-
-
-def retrieve_issue(gitlab_url, project_id, issue_id):
-    url = f"{gitlab_url}/api/v4/projects/{project_id}/issues/{issue_id}"
-    response = requests.get(url)
-    response.raise_for_status()
-    return response.json()
-
-
-def retrieve_issue_page(url):
-    response = requests.get(url)
-    response.raise_for_status()
-
-    links = response.links
-    next_page = None
-    if links and links.get("next"):
-        next_page = links["next"]["url"]
-    return response.json(), next_page
-
-
-def import_contributor_from_author(payload):
-    contributor = None
-    try:
-        contributor = core_models.Contributor.objects.get(
-            username__iexact=payload["username"]
-        )
-    except core_models.Contributor.DoesNotExist:
-        return core_models.Contributor.objects.create(
-            username=payload["username"],
-            name=payload["name"],
-            metadata={"gitlab": payload},
-        )
-
-    contributor.metadata["gitlab"] = payload
-    contributor.save(update_fields=["metadata"])
-    return contributor
-
-
-def import_issue_as_contribution(payload, project_name):
-    contributor = import_contributor_from_author(payload["author"])
-    parsed_url = urllib.parse.urlparse(payload["_links"]["self"])
-    project_url = f"{parsed_url.scheme}://{parsed_url.netloc}/{project_name}"
-    external_id = payload["_links"]["self"]
-    defaults = {
-        "summary": payload["title"],
-        "contributor": contributor,
-        "type": "dev:issue",
-        "creation_date": pendulum.parse(payload["created_at"]),
-        "import_date": timezone.now(),
-        "is_visible": True,
-        "url": payload["web_url"],
-        "metadata": {
-            "labels": payload["labels"],
-            "id": payload["iid"],
-            "project": project_name,
-            "project_url": project_url,
-        },
-    }
-
-    return core_models.Contribution.objects.update_or_create(
-        external_id=external_id, defaults=defaults
-    )[0]
diff --git a/contributions/sources/opencollective.py b/contributions/sources/opencollective.py
deleted file mode 100644
index c8fe27537b6ff86cb908fc6ab0adfe496b0ae507..0000000000000000000000000000000000000000
--- a/contributions/sources/opencollective.py
+++ /dev/null
@@ -1,104 +0,0 @@
-import datetime
-import requests
-
-from django.utils import timezone
-
-from contributions.core import models as core_models
-
-ENDPOINT = "https://opencollective.com/api/graphql"
-DATE_FORMAT = "%a %b %d %Y %H:%M:%S GMT%z (%Z)"
-
-TRANSACTIONS_QUERY = {
-    "operationName": "Transactions",
-    "query": """
-        query Transactions($CollectiveId: Int!, $type: String, $limit: Int, $offset: Int, $dateFrom: String, $dateTo: String) {
-            allTransactions(CollectiveId: $CollectiveId, type: $type, limit: $limit, offset: $offset, dateFrom: $dateFrom, dateTo: $dateTo) {
-                id
-                uuid
-                description
-                createdAt
-                type
-                amount
-                currency
-                hostCurrency
-                hostCurrencyFxRate
-                fromCollective {
-                    id
-                    name
-                    slug
-                    path
-                    image
-                    __typename
-                }
-                ... on Expense {
-                    category
-                    attachment
-                    __typename
-                }
-                ... on Order {
-                    createdAt
-                    subscription {
-                        interval
-                        __typename
-                    }
-                    __typename
-                }
-            __typename
-        }
-    }""",
-}
-
-
-def retrieve_transactions(collective_id, limit=100, offset=0):
-    query = TRANSACTIONS_QUERY.copy()
-    query["variables"] = {
-        "CollectiveId": collective_id,
-        "limit": limit,
-        "offset": offset,
-    }
-    response = requests.post(ENDPOINT, json=query)
-    response.raise_for_status()
-    return response.json()["data"]["allTransactions"]
-
-
-def import_contributor(payload):
-    contributor = None
-    payload["web_url"] = f"https://opencollective.com/{payload['slug']}"
-    try:
-        contributor = core_models.Contributor.objects.get(
-            username__iexact=payload["slug"]
-        )
-    except core_models.Contributor.DoesNotExist:
-        return core_models.Contributor.objects.create(
-            username=payload["slug"],
-            name=payload["name"],
-            metadata={"opencollective": payload},
-        )
-
-    contributor.metadata["opencollective"] = payload
-    contributor.save(update_fields=["metadata"])
-    return contributor
-
-
-def import_transaction_as_contribution(payload, collective):
-    contributor = import_contributor(payload["fromCollective"].copy())
-    creation_date = datetime.datetime.strptime(payload["createdAt"], DATE_FORMAT)
-    defaults = {
-        "summary": payload["description"],
-        "contributor": contributor,
-        "type": "donation",
-        "creation_date": creation_date,
-        "import_date": timezone.now(),
-        "is_visible": True,
-        "url": None,
-        "external_id": payload["id"],
-        "metadata": payload,
-    }
-    defaults["metadata"]["amount"] = payload["amount"]
-    defaults["metadata"]["currency"] = payload["currency"]
-    defaults["metadata"]["project_url"] = f"https://opencollective.com/{collective}"
-    defaults["metadata"]["collective"] = collective
-
-    return core_models.Contribution.objects.update_or_create(
-        external_id=payload["id"], defaults=defaults
-    )[0]
diff --git a/contributions/users/__init__.py b/contributions/users/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/contributions/users/adapters.py b/contributions/users/adapters.py
deleted file mode 100644
index 9361d6eca7815eb4cb3e1e56c0c8ca7f39fad0a7..0000000000000000000000000000000000000000
--- a/contributions/users/adapters.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from typing import Any
-
-from allauth.account.adapter import DefaultAccountAdapter
-from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
-from django.conf import settings
-from django.http import HttpRequest
-
-
-class AccountAdapter(DefaultAccountAdapter):
-
-    def is_open_for_signup(self, request: HttpRequest):
-        return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
-
-
-class SocialAccountAdapter(DefaultSocialAccountAdapter):
-
-    def is_open_for_signup(self, request: HttpRequest, sociallogin: Any):
-        return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
diff --git a/contributions/users/admin.py b/contributions/users/admin.py
deleted file mode 100644
index 42b524f10a3e27e1eb2c3605696bbbbeeb2ea0cf..0000000000000000000000000000000000000000
--- a/contributions/users/admin.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from django.contrib import admin
-from django.contrib.auth import admin as auth_admin
-from django.contrib.auth import get_user_model
-
-User = get_user_model()
-
-
-@admin.register(User)
-class UserAdmin(auth_admin.UserAdmin):
-
-    fieldsets = (("User", {"fields": ("name",)}),) + auth_admin.UserAdmin.fieldsets
-    list_display = ["username", "name", "is_superuser"]
-    search_fields = ["name"]
diff --git a/contributions/users/apps.py b/contributions/users/apps.py
deleted file mode 100644
index b4770df417c6dec4740c9d5222067a7a41ca6fd6..0000000000000000000000000000000000000000
--- a/contributions/users/apps.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from django.apps import AppConfig
-
-
-class UsersAppConfig(AppConfig):
-
-    name = "contributions.users"
-    verbose_name = "Users"
-
-    def ready(self):
-        try:
-            import users.signals  # noqa F401
-        except ImportError:
-            pass
diff --git a/contributions/users/migrations/0001_initial.py b/contributions/users/migrations/0001_initial.py
deleted file mode 100644
index c9d8905688fe3074fdaf8087fbd7bf1d6e1354b4..0000000000000000000000000000000000000000
--- a/contributions/users/migrations/0001_initial.py
+++ /dev/null
@@ -1,132 +0,0 @@
-import django.contrib.auth.models
-import django.contrib.auth.validators
-from django.db import migrations, models
-import django.utils.timezone
-
-
-class Migration(migrations.Migration):
-
-    initial = True
-
-    dependencies = [("auth", "0008_alter_user_username_max_length")]
-
-    operations = [
-        migrations.CreateModel(
-            name="User",
-            fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                ("password", models.CharField(max_length=128, verbose_name="password")),
-                (
-                    "last_login",
-                    models.DateTimeField(
-                        blank=True, null=True, verbose_name="last login"
-                    ),
-                ),
-                (
-                    "is_superuser",
-                    models.BooleanField(
-                        default=False,
-                        help_text="Designates that this user has all permissions without explicitly assigning them.",
-                        verbose_name="superuser status",
-                    ),
-                ),
-                (
-                    "username",
-                    models.CharField(
-                        error_messages={
-                            "unique": "A user with that username already exists."
-                        },
-                        help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
-                        max_length=150,
-                        unique=True,
-                        validators=[
-                            django.contrib.auth.validators.UnicodeUsernameValidator()
-                        ],
-                        verbose_name="username",
-                    ),
-                ),
-                (
-                    "first_name",
-                    models.CharField(
-                        blank=True, max_length=30, verbose_name="first name"
-                    ),
-                ),
-                (
-                    "last_name",
-                    models.CharField(
-                        blank=True, max_length=150, verbose_name="last name"
-                    ),
-                ),
-                (
-                    "email",
-                    models.EmailField(
-                        blank=True, max_length=254, verbose_name="email address"
-                    ),
-                ),
-                (
-                    "is_staff",
-                    models.BooleanField(
-                        default=False,
-                        help_text="Designates whether the user can log into this admin site.",
-                        verbose_name="staff status",
-                    ),
-                ),
-                (
-                    "is_active",
-                    models.BooleanField(
-                        default=True,
-                        help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
-                        verbose_name="active",
-                    ),
-                ),
-                (
-                    "date_joined",
-                    models.DateTimeField(
-                        default=django.utils.timezone.now, verbose_name="date joined"
-                    ),
-                ),
-                (
-                    "name",
-                    models.CharField(
-                        blank=True, max_length=255, verbose_name="Name of User"
-                    ),
-                ),
-                (
-                    "groups",
-                    models.ManyToManyField(
-                        blank=True,
-                        help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
-                        related_name="user_set",
-                        related_query_name="user",
-                        to="auth.Group",
-                        verbose_name="groups",
-                    ),
-                ),
-                (
-                    "user_permissions",
-                    models.ManyToManyField(
-                        blank=True,
-                        help_text="Specific permissions for this user.",
-                        related_name="user_set",
-                        related_query_name="user",
-                        to="auth.Permission",
-                        verbose_name="user permissions",
-                    ),
-                ),
-            ],
-            options={
-                "verbose_name_plural": "users",
-                "verbose_name": "user",
-                "abstract": False,
-            },
-            managers=[("objects", django.contrib.auth.models.UserManager())],
-        )
-    ]
diff --git a/contributions/users/migrations/__init__.py b/contributions/users/migrations/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/contributions/users/models.py b/contributions/users/models.py
deleted file mode 100644
index 8f07b15a119e450d0ba5f4933e5c1d0a9202aaa9..0000000000000000000000000000000000000000
--- a/contributions/users/models.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from django.contrib.auth.models import AbstractUser
-from django.db.models import CharField
-from django.urls import reverse
-from django.utils.translation import ugettext_lazy as _
-
-
-class User(AbstractUser):
-
-    # First Name and Last Name do not cover name patterns
-    # around the globe.
-    name = CharField(_("Name of User"), blank=True, max_length=255)
-
-    def get_absolute_url(self):
-        return reverse("users:detail", kwargs={"username": self.username})
diff --git a/front/.gitignore b/front/.gitignore
deleted file mode 100644
index 185e6631928dca2f51224e61a3861cc88fa2b74e..0000000000000000000000000000000000000000
--- a/front/.gitignore
+++ /dev/null
@@ -1,21 +0,0 @@
-.DS_Store
-node_modules
-/dist
-
-# local env files
-.env.local
-.env.*.local
-
-# Log files
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# Editor directories and files
-.idea
-.vscode
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw*
diff --git a/local.yml b/local.yml
deleted file mode 100644
index 48733ccb67d927f4784b1b0d773fb0d8c2bcf6b1..0000000000000000000000000000000000000000
--- a/local.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-version: '3'
-
-services:
-  django:
-    build:
-      context: .
-      dockerfile: ./compose/local/django/Dockerfile
-    image: contributions_local_django
-    depends_on:
-      - postgres
-    volumes:
-      - .:/app
-    env_file:
-      - ./.envs/.local/.django
-      - ./.envs/.local/.postgres
-    ports:
-      - "8000:8000"
-    command: /start
-
-  postgres:
-    build:
-      context: .
-      dockerfile: ./compose/production/postgres/Dockerfile
-    image: contributions_production_postgres
-    volumes:
-      - ./data/postgres:/var/lib/postgresql/data
-    env_file:
-      - ./.envs/.local/.postgres
diff --git a/front/locales/app.pot b/locales/app.pot
similarity index 100%
rename from front/locales/app.pot
rename to locales/app.pot
diff --git a/front/locales/en_US/LC_MESSAGES/app.po b/locales/en_US/LC_MESSAGES/app.po
similarity index 100%
rename from front/locales/en_US/LC_MESSAGES/app.po
rename to locales/en_US/LC_MESSAGES/app.po
diff --git a/front/locales/fr_FR/LC_MESSAGES/app.po b/locales/fr_FR/LC_MESSAGES/app.po
similarity index 100%
rename from front/locales/fr_FR/LC_MESSAGES/app.po
rename to locales/fr_FR/LC_MESSAGES/app.po
diff --git a/manage.py b/manage.py
deleted file mode 100755
index c3019f0c043b3083c86e18f7c1bf355b9f85990d..0000000000000000000000000000000000000000
--- a/manage.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env python
-import os
-import sys
-
-if __name__ == "__main__":
-    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
-
-    try:
-        from django.core.management import execute_from_command_line
-    except ImportError:
-        # The above import may fail for some other reason. Ensure that the
-        # issue is really that Django is missing to avoid masking other
-        # exceptions on Python 2.
-        try:
-            import django  # noqa
-        except ImportError:
-            raise ImportError(
-                "Couldn't import Django. Are you sure it's installed and "
-                "available on your PYTHONPATH environment variable? Did you "
-                "forget to activate a virtual environment?"
-            )
-
-        raise
-
-    # This allows easy placement of apps within the interior
-    # contributions directory.
-    current_path = os.path.dirname(os.path.abspath(__file__))
-    sys.path.append(os.path.join(current_path, "contributions"))
-
-    execute_from_command_line(sys.argv)
diff --git a/merge_production_dotenvs_in_dotenv.py b/merge_production_dotenvs_in_dotenv.py
deleted file mode 100644
index 5c3027a40b4000e0348102aa079022798947c506..0000000000000000000000000000000000000000
--- a/merge_production_dotenvs_in_dotenv.py
+++ /dev/null
@@ -1,67 +0,0 @@
-import os
-from typing import Sequence
-
-import pytest
-
-ROOT_DIR_PATH = os.path.dirname(os.path.realpath(__file__))
-PRODUCTION_DOTENVS_DIR_PATH = os.path.join(ROOT_DIR_PATH, ".envs", ".production")
-PRODUCTION_DOTENV_FILE_PATHS = [
-    os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".django"),
-    os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".postgres"),
-    os.path.join(PRODUCTION_DOTENVS_DIR_PATH, ".caddy"),
-]
-DOTENV_FILE_PATH = os.path.join(ROOT_DIR_PATH, ".env")
-
-
-def merge(
-    output_file_path: str, merged_file_paths: Sequence[str], append_linesep: bool = True
-) -> None:
-    with open(output_file_path, "w") as output_file:
-        for merged_file_path in merged_file_paths:
-            with open(merged_file_path, "r") as merged_file:
-                merged_file_content = merged_file.read()
-                output_file.write(merged_file_content)
-                if append_linesep:
-                    output_file.write(os.linesep)
-
-
-def main():
-    merge(DOTENV_FILE_PATH, PRODUCTION_DOTENV_FILE_PATHS)
-
-
-@pytest.mark.parametrize("merged_file_count", range(3))
-@pytest.mark.parametrize("append_linesep", [True, False])
-def test_merge(tmpdir_factory, merged_file_count: int, append_linesep: bool):
-    tmp_dir_path = str(tmpdir_factory.getbasetemp())
-
-    output_file_path = os.path.join(tmp_dir_path, ".env")
-
-    expected_output_file_content = ""
-    merged_file_paths = []
-    for i in range(merged_file_count):
-        merged_file_ord = i + 1
-
-        merged_filename = ".service{}".format(merged_file_ord)
-        merged_file_path = os.path.join(tmp_dir_path, merged_filename)
-
-        merged_file_content = merged_filename * merged_file_ord
-
-        with open(merged_file_path, "w+") as file:
-            file.write(merged_file_content)
-
-        expected_output_file_content += merged_file_content
-        if append_linesep:
-            expected_output_file_content += os.linesep
-
-        merged_file_paths.append(merged_file_path)
-
-    merge(output_file_path, merged_file_paths, append_linesep)
-
-    with open(output_file_path, "r") as output_file:
-        actual_output_file_content = output_file.read()
-
-    assert actual_output_file_content == expected_output_file_content
-
-
-if __name__ == "__main__":
-    main()
diff --git a/front/package.json b/package.json
similarity index 100%
rename from front/package.json
rename to package.json
diff --git a/production.yml b/production.yml
deleted file mode 100644
index 22121f712113aad9b279b03051a7f19f61a63da9..0000000000000000000000000000000000000000
--- a/production.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-version: '3'
-
-volumes:
-  production_postgres_data: {}
-  production_postgres_data_backups: {}
-  production_caddy: {}
-
-services:
-  django:
-    build:
-      context: .
-      dockerfile: ./compose/production/django/Dockerfile
-    image: contributions_production_django
-    depends_on:
-      - postgres
-      - redis
-    env_file:
-      - ./.envs/.production/.django
-      - ./.envs/.production/.postgres
-    command: /start
-
-  postgres:
-    build:
-      context: .
-      dockerfile: ./compose/production/postgres/Dockerfile
-    image: contributions_production_postgres
-    volumes:
-      - production_postgres_data:/var/lib/postgresql/data
-      - production_postgres_data_backups:/backups
-    env_file:
-      - ./.envs/.production/.postgres
-
-  caddy:
-    build:
-      context: .
-      dockerfile: ./compose/production/caddy/Dockerfile
-    image: contributions_production_caddy
-    depends_on:
-      - django
-    volumes:
-      - production_caddy:/root/.caddy
-    env_file:
-      - ./.envs/.production/.caddy
-    ports:
-      - "0.0.0.0:80:80"
-      - "0.0.0.0:443:443"
-
-  redis:
-    image: redis:3.2
diff --git a/front/public/assets/guides/backer/tier-backer.png b/public/assets/guides/backer/tier-backer.png
similarity index 100%
rename from front/public/assets/guides/backer/tier-backer.png
rename to public/assets/guides/backer/tier-backer.png
diff --git a/front/public/assets/guides/backer/tier-one-time.png b/public/assets/guides/backer/tier-one-time.png
similarity index 100%
rename from front/public/assets/guides/backer/tier-one-time.png
rename to public/assets/guides/backer/tier-one-time.png
diff --git a/front/public/assets/guides/backer/tier-sponsor.png b/public/assets/guides/backer/tier-sponsor.png
similarity index 100%
rename from front/public/assets/guides/backer/tier-sponsor.png
rename to public/assets/guides/backer/tier-sponsor.png
diff --git a/front/public/assets/guides/gitlab-account/login-form.png b/public/assets/guides/gitlab-account/login-form.png
similarity index 100%
rename from front/public/assets/guides/gitlab-account/login-form.png
rename to public/assets/guides/gitlab-account/login-form.png
diff --git a/front/public/assets/guides/gitlab-account/profile-form.png b/public/assets/guides/gitlab-account/profile-form.png
similarity index 100%
rename from front/public/assets/guides/gitlab-account/profile-form.png
rename to public/assets/guides/gitlab-account/profile-form.png
diff --git a/front/public/assets/guides/gitlab-account/signup-form.png b/public/assets/guides/gitlab-account/signup-form.png
similarity index 100%
rename from front/public/assets/guides/gitlab-account/signup-form.png
rename to public/assets/guides/gitlab-account/signup-form.png
diff --git a/front/public/assets/guides/gitlab-account/user-dropdown.png b/public/assets/guides/gitlab-account/user-dropdown.png
similarity index 100%
rename from front/public/assets/guides/gitlab-account/user-dropdown.png
rename to public/assets/guides/gitlab-account/user-dropdown.png
diff --git a/front/public/assets/guides/translate/language-list.png b/public/assets/guides/translate/language-list.png
similarity index 100%
rename from front/public/assets/guides/translate/language-list.png
rename to public/assets/guides/translate/language-list.png
diff --git a/front/public/assets/guides/translate/login-form.png b/public/assets/guides/translate/login-form.png
similarity index 100%
rename from front/public/assets/guides/translate/login-form.png
rename to public/assets/guides/translate/login-form.png
diff --git a/front/public/assets/guides/translate/profile-languages.png b/public/assets/guides/translate/profile-languages.png
similarity index 100%
rename from front/public/assets/guides/translate/profile-languages.png
rename to public/assets/guides/translate/profile-languages.png
diff --git a/front/public/assets/guides/translate/translate-button.png b/public/assets/guides/translate/translate-button.png
similarity index 100%
rename from front/public/assets/guides/translate/translate-button.png
rename to public/assets/guides/translate/translate-button.png
diff --git a/front/public/assets/guides/translate/translation-form-action-bar.png b/public/assets/guides/translate/translation-form-action-bar.png
similarity index 100%
rename from front/public/assets/guides/translate/translation-form-action-bar.png
rename to public/assets/guides/translate/translation-form-action-bar.png
diff --git a/front/public/assets/guides/translate/translation-form-check.png b/public/assets/guides/translate/translation-form-check.png
similarity index 100%
rename from front/public/assets/guides/translate/translation-form-check.png
rename to public/assets/guides/translate/translation-form-check.png
diff --git a/front/public/assets/guides/translate/translation-form-complete.png b/public/assets/guides/translate/translation-form-complete.png
similarity index 100%
rename from front/public/assets/guides/translate/translation-form-complete.png
rename to public/assets/guides/translate/translation-form-complete.png
diff --git a/front/public/assets/guides/translate/translation-form-menu.png b/public/assets/guides/translate/translation-form-menu.png
similarity index 100%
rename from front/public/assets/guides/translate/translation-form-menu.png
rename to public/assets/guides/translate/translation-form-menu.png
diff --git a/front/public/assets/guides/translate/translation-form-source.png b/public/assets/guides/translate/translation-form-source.png
similarity index 100%
rename from front/public/assets/guides/translate/translation-form-source.png
rename to public/assets/guides/translate/translation-form-source.png
diff --git a/front/public/assets/guides/translate/translation-form-translate-area.png b/public/assets/guides/translate/translation-form-translate-area.png
similarity index 100%
rename from front/public/assets/guides/translate/translation-form-translate-area.png
rename to public/assets/guides/translate/translation-form-translate-area.png
diff --git a/front/public/favicon.ico b/public/favicon.ico
similarity index 100%
rename from front/public/favicon.ico
rename to public/favicon.ico
diff --git a/front/public/index.html b/public/index.html
similarity index 100%
rename from front/public/index.html
rename to public/index.html
diff --git a/front/public/logo-full.png b/public/logo-full.png
similarity index 100%
rename from front/public/logo-full.png
rename to public/logo-full.png
diff --git a/pytest.ini b/pytest.ini
deleted file mode 100644
index 36617795ad5f63dd4e96db67193b678d1d36e1ec..0000000000000000000000000000000000000000
--- a/pytest.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[pytest]
-DJANGO_SETTINGS_MODULE=config.settings.test
-testpaths = tests
diff --git a/requirements/base.txt b/requirements/base.txt
deleted file mode 100644
index 119c423b1e08cfc9d32608f1a327741d67e1f462..0000000000000000000000000000000000000000
--- a/requirements/base.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-pytz==2018.5  # https://github.com/stub42/pytz
-python-slugify==1.2.6  # https://github.com/un33k/python-slugify
-redis>=2.10.5  # https://github.com/antirez/redis
-
-# Django
-# ------------------------------------------------------------------------------
-django>=2.1,<2.2
-django-environ==0.4.5  # https://github.com/joke2k/django-environ
-django-allauth>=0.37,<0.38  # https://github.com/pennersr/django-allauth
-django-redis==4.9.0  # https://github.com/niwinz/django-redis
-
-# Django REST Framework
-djangorestframework>=3.8,<3.9  # https://github.com/encode/django-rest-framework
-psycopg2==2.7.4 --no-binary psycopg2  # https://github.com/psycopg/psycopg2
-requests
-pendulum
-django-cors-headers
-django-filter
diff --git a/requirements/local.txt b/requirements/local.txt
deleted file mode 100644
index 0af83ecb1c01071c3d4642a4f4b125dd6fff9356..0000000000000000000000000000000000000000
--- a/requirements/local.txt
+++ /dev/null
@@ -1,27 +0,0 @@
--r ./base.txt
-
-Werkzeug==0.14.1  # https://github.com/pallets/werkzeug
-ipdb==0.11  # https://github.com/gotcha/ipdb
-psycopg2==2.7.4 --no-binary psycopg2  # https://github.com/psycopg/psycopg2
-
-# Testing
-# ------------------------------------------------------------------------------
-mypy==0.630  # https://github.com/python/mypy
-pytest==3.8.1  # https://github.com/pytest-dev/pytest
-pytest-sugar==0.9.1  # https://github.com/Frozenball/pytest-sugar
-
-# Code quality
-# ------------------------------------------------------------------------------
-flake8==3.5.0  # https://github.com/PyCQA/flake8
-coverage==4.5.1  # https://github.com/nedbat/coveragepy
-
-# Django
-# ------------------------------------------------------------------------------
-factory-boy==2.11.1  # https://github.com/FactoryBoy/factory_boy
-
-django-debug-toolbar==1.10.1  # https://github.com/jazzband/django-debug-toolbar
-django-extensions==2.1.3  # https://github.com/django-extensions/django-extensions
-django-coverage-plugin==1.6.0  # https://github.com/nedbat/django_coverage_plugin
-pytest-django==3.4.3  # https://github.com/pytest-dev/pytest-django
-requests-mock==1.5.2
-pytest-mock==1.10.0
diff --git a/requirements/production.txt b/requirements/production.txt
deleted file mode 100644
index eb98a76f21ff1a2fbc063d19d94726dff5519a8e..0000000000000000000000000000000000000000
--- a/requirements/production.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-# PRECAUTION: avoid production dependencies that aren't in development
-
--r ./base.txt
-
-gunicorn==19.8.1  # https://github.com/benoitc/gunicorn
diff --git a/front/scripts/i18n-compile.sh b/scripts/i18n-compile.sh
similarity index 100%
rename from front/scripts/i18n-compile.sh
rename to scripts/i18n-compile.sh
diff --git a/front/scripts/i18n-extract.sh b/scripts/i18n-extract.sh
similarity index 100%
rename from front/scripts/i18n-extract.sh
rename to scripts/i18n-extract.sh
diff --git a/front/scripts/i18n-weblate-to-origin.sh b/scripts/i18n-weblate-to-origin.sh
similarity index 100%
rename from front/scripts/i18n-weblate-to-origin.sh
rename to scripts/i18n-weblate-to-origin.sh
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index c2139f1db33b9595c9bda4ef8c1459a942ee8433..0000000000000000000000000000000000000000
--- a/setup.cfg
+++ /dev/null
@@ -1,21 +0,0 @@
-[flake8]
-max-line-length = 120
-exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
-
-[pycodestyle]
-max-line-length = 120
-exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
-
-[mypy]
-python_version = 3.6
-check_untyped_defs = True
-ignore_errors = False
-ignore_missing_imports = True
-strict_optional = True
-warn_unused_ignores = True
-warn_redundant_casts = True
-warn_unused_configs = True
-
-[mypy-*.migrations.*]
-# Django migrations should not produce any errors:
-ignore_errors = True
diff --git a/front/src/App.vue b/src/App.vue
similarity index 100%
rename from front/src/App.vue
rename to src/App.vue
diff --git a/front/src/assets/logo.png b/src/assets/logo.png
similarity index 100%
rename from front/src/assets/logo.png
rename to src/assets/logo.png
diff --git a/front/src/components/ContributionItem.vue b/src/components/ContributionItem.vue
similarity index 100%
rename from front/src/components/ContributionItem.vue
rename to src/components/ContributionItem.vue
diff --git a/front/src/components/Donation.vue b/src/components/Donation.vue
similarity index 100%
rename from front/src/components/Donation.vue
rename to src/components/Donation.vue
diff --git a/front/src/components/Icon.vue b/src/components/Icon.vue
similarity index 100%
rename from front/src/components/Icon.vue
rename to src/components/Icon.vue
diff --git a/front/src/components/Issue.vue b/src/components/Issue.vue
similarity index 100%
rename from front/src/components/Issue.vue
rename to src/components/Issue.vue
diff --git a/front/src/components/Modal.vue b/src/components/Modal.vue
similarity index 100%
rename from front/src/components/Modal.vue
rename to src/components/Modal.vue
diff --git a/front/src/components/Task.vue b/src/components/Task.vue
similarity index 100%
rename from front/src/components/Task.vue
rename to src/components/Task.vue
diff --git a/front/src/components/globals.js b/src/components/globals.js
similarity index 100%
rename from front/src/components/globals.js
rename to src/components/globals.js
diff --git a/front/src/components/guide/Content.vue b/src/components/guide/Content.vue
similarity index 100%
rename from front/src/components/guide/Content.vue
rename to src/components/guide/Content.vue
diff --git a/front/src/components/guide/Image.vue b/src/components/guide/Image.vue
similarity index 100%
rename from front/src/components/guide/Image.vue
rename to src/components/guide/Image.vue
diff --git a/front/src/components/guide/Menu.vue b/src/components/guide/Menu.vue
similarity index 100%
rename from front/src/components/guide/Menu.vue
rename to src/components/guide/Menu.vue
diff --git a/front/src/components/guide/Step.vue b/src/components/guide/Step.vue
similarity index 100%
rename from front/src/components/guide/Step.vue
rename to src/components/guide/Step.vue
diff --git a/front/src/locales.js b/src/locales.js
similarity index 100%
rename from front/src/locales.js
rename to src/locales.js
diff --git a/front/src/main.js b/src/main.js
similarity index 100%
rename from front/src/main.js
rename to src/main.js
diff --git a/front/src/mixins/TaskMixin.js b/src/mixins/TaskMixin.js
similarity index 100%
rename from front/src/mixins/TaskMixin.js
rename to src/mixins/TaskMixin.js
diff --git a/front/src/router.js b/src/router.js
similarity index 100%
rename from front/src/router.js
rename to src/router.js
diff --git a/front/src/views/Guide.vue b/src/views/Guide.vue
similarity index 100%
rename from front/src/views/Guide.vue
rename to src/views/Guide.vue
diff --git a/front/src/views/Home.vue b/src/views/Home.vue
similarity index 100%
rename from front/src/views/Home.vue
rename to src/views/Home.vue
diff --git a/tests/__init__.py b/tests/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/tests/conftest.py b/tests/conftest.py
deleted file mode 100644
index e8feb802baf99a3a04d995f6c2e33c99b0e78b49..0000000000000000000000000000000000000000
--- a/tests/conftest.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import pytest
-from django.conf import settings
-from django.test import RequestFactory
-from django.utils import timezone
-
-from . import factories as test_factories
-
-
-@pytest.fixture
-def request_factory() -> RequestFactory:
-    return RequestFactory()
-
-
-@pytest.fixture
-def factories(db) -> test_factories:
-    return test_factories
-
-
-@pytest.fixture
-def nodb_factories() -> test_factories:
-    return test_factories
-
-
-@pytest.fixture
-def now(mocker):
-    n = timezone.now()
-    mocker.patch.object(timezone, 'now', return_value=n)
-    return n
diff --git a/tests/factories.py b/tests/factories.py
deleted file mode 100644
index d88e384c3732235dbdecbc3274396e6c4a34ba04..0000000000000000000000000000000000000000
--- a/tests/factories.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import factory
-
-from contributions.core import models as core_models
-
-
-class Contributor(factory.DjangoModelFactory):
-    name = factory.Faker('name')
-    metadata = factory.LazyAttribute(lambda o: {})
-
-    class Meta:
-        model = core_models.Contributor
-
-
-class Contribution(factory.DjangoModelFactory):
-    contributor = factory.SubFactory(Contributor)
-    summary = factory.Faker('paragraph')
-    type = factory.Iterator([t[0] for t in core_models.CONTRIBUTION_TYPES])
-    external_id = factory.Faker('uuid4')
-    url = factory.Faker('url')
-    metadata = factory.LazyAttribute(lambda o: {})
-
-    class Meta:
-        model = core_models.Contribution
diff --git a/tests/test_gitlab.py b/tests/test_gitlab.py
deleted file mode 100644
index 8c317bf418548f2c507c51634499e6c33ce9affc..0000000000000000000000000000000000000000
--- a/tests/test_gitlab.py
+++ /dev/null
@@ -1,100 +0,0 @@
-from contributions.sources import gitlab
-import pendulum
-
-
-def test_retrieve_issue(requests_mock):
-    gitlab_url = "https://gitlab.test"
-    project_id = 1
-    issue_id = 42
-
-    requests_mock.get(
-        f"https://gitlab.test/api/v4/projects/{project_id}/issues/{issue_id}",
-        json={"hello": "world"},
-    )
-    result = gitlab.retrieve_issue(gitlab_url, project_id, issue_id)
-
-    assert result == {"hello": "world"}
-
-
-def test_import_issue_as_contribution(now, db):
-    project_name = "awesome/project"
-    issue_payload = {
-        "id": 703,
-        "iid": 559,
-        "project_id": 17,
-        "title": "My awesome issue",
-        "created_at": "2018-10-05T15:23:17.257Z",
-        "labels": ["tag1", "tag2", "tag3"],
-        "author": {
-            "id": 130,
-            "name": "Alice",
-            "username": "Alice42",
-            "avatar_url": "https://secure.gravatar.com/avatar/1ed9cb8b4bdad28157104cd2f9468b3f?s=80\u0026d=identicon",
-            "web_url": "https://gitlab.test/Alice42",
-        },
-        "web_url": "https://gitlab.test/awesome/project/issues/559",
-        "_links": {"self": "https://gitlab.test/api/v4/projects/17/issues/559"},
-    }
-
-    contribution = gitlab.import_issue_as_contribution(issue_payload, project_name)
-
-    contributor = contribution.contributor
-
-    assert contributor.name == issue_payload["author"]["name"]
-    assert contributor.username == issue_payload["author"]["username"]
-    assert contributor.metadata == {"gitlab": issue_payload["author"]}
-
-    assert contribution.summary == issue_payload["title"]
-    assert contribution.type == "dev:issue"
-    assert contribution.creation_date == pendulum.parse(issue_payload["created_at"])
-    assert contribution.import_date == now
-    assert contribution.is_visible is True
-    assert contribution.external_id == issue_payload["_links"]["self"]
-    assert contribution.url == issue_payload["web_url"]
-    assert contribution.metadata == {
-        "labels": issue_payload["labels"],
-        "id": issue_payload["iid"],
-        "project": project_name,
-        "project_url": f"https://gitlab.test/{project_name}",
-    }
-
-
-def test_import_contributor_create(db):
-    payload = {"id": 130, "name": "Alice", "username": "Alice42"}
-
-    contributor = gitlab.import_contributor_from_author(payload)
-
-    assert contributor.name == payload["name"]
-    assert contributor.username == payload["username"]
-    assert contributor.metadata == {"gitlab": payload}
-
-
-def test_import_contributor_update_metadata(factories):
-    existing = factories.Contributor(username="Alice42", metadata={"hello": "world"})
-    payload = {"id": 130, "name": "Alice", "username": "Alice42"}
-
-    contributor = gitlab.import_contributor_from_author(payload)
-
-    assert contributor == existing
-    assert contributor.name == existing.name
-    assert contributor.username == existing.username
-    assert contributor.metadata == {"gitlab": payload, "hello": "world"}
-
-
-def test_retrieve_issue_page(requests_mock):
-    gitlab_url = "https://gitlab.test"
-    project_id = 1
-    url = f"{gitlab_url}/api/v4/projects/{project_id}/issues"
-
-    expected_next_page = (
-        f"https://gitlab.test/api/v4/projects/{project_id}/issues?page=2"
-    )
-    requests_mock.get(
-        f"https://gitlab.test/api/v4/projects/{project_id}/issues",
-        json=["hello", "world"],
-        headers={"Link": f'<{expected_next_page}>; rel="next"'},
-    )
-    result, next_page = gitlab.retrieve_issue_page(url)
-
-    assert result == ["hello", "world"]
-    assert expected_next_page == next_page
diff --git a/tests/test_models.py b/tests/test_models.py
deleted file mode 100644
index 2c64ebb22b51d4f6ed552ff4c9d9bb01486bd1cf..0000000000000000000000000000000000000000
--- a/tests/test_models.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from django.utils import timezone
-
-from contributions.core import models as core_models
-
-
-def test_contributor_factory(factories):
-    contributor = factories.Contributor(
-        name="alice", is_visible=True, metadata={"hello": "world"}
-    )
-
-    assert contributor.name == "alice"
-    assert contributor.creation_date < timezone.now()
-    assert contributor.is_visible is True
-    assert contributor.metadata == {"hello": "world"}
-
-
-def test_contribution_factory(factories):
-    contribution = factories.Contribution(
-        external_id="weblate:front",
-        metadata={"locale": "en"},
-        is_visible=True,
-        url="https://weblate.test",
-        summary="Hello",
-        type="i18n:translation",
-    )
-
-    assert isinstance(contribution.contributor, core_models.Contributor)
-    assert contribution.creation_date < timezone.now()
-    assert contribution.import_date < timezone.now()
-    assert contribution.is_visible is True
-    assert contribution.metadata == {"locale": "en"}
-    assert contribution.summary == "Hello"
-    assert contribution.type == "i18n:translation"
-    assert contribution.external_id == "weblate:front"
-    assert contribution.url == "https://weblate.test"
diff --git a/tests/test_open_collective.py b/tests/test_open_collective.py
deleted file mode 100644
index 87711e02af33078ec0a1326698c4778162ffd83f..0000000000000000000000000000000000000000
--- a/tests/test_open_collective.py
+++ /dev/null
@@ -1,118 +0,0 @@
-from contributions.sources import opencollective
-
-import datetime
-
-
-def test_retrieve_transactions(requests_mock):
-    expected_query = opencollective.TRANSACTIONS_QUERY.copy()
-    expected_query["variables"] = {"CollectiveId": 42, "limit": 5, "offset": 3}
-    graphql = requests_mock.post(
-        opencollective.ENDPOINT, json={"data": {"allTransactions": {"hello": "world"}}}
-    )
-    result = opencollective.retrieve_transactions(collective_id=42, limit=5, offset=3)
-    request = graphql.request_history[0]
-
-    assert result == {"hello": "world"}
-    assert request.json() == expected_query
-
-
-def test_import_transaction_as_contribution(now, db):
-    transaction_payload = {
-        "__typename": "Order",
-        "amount": 100,
-        "createdAt": "Mon Oct 15 2018 22:49:53 GMT+0000 (UTC)",
-        "currency": "EUR",
-        "description": "Monthly donation to Funkwhale (Backer)",
-        "fromCollective": {
-            "__typename": "User",
-            "id": 22538,
-            "image": "https://www.gravatar.com/avatar/1bf34eec3e0e8a1b6a818103ee6619e1?default=404",
-            "name": "Alice",
-            "path": "/alice",
-            "slug": "alice",
-        },
-        "hostCurrency": "EUR",
-        "hostCurrencyFxRate": 1,
-        "hostFeeInHostCurrency": -5,
-        "id": 125_616,
-        "netAmountInCollectiveCurrency": 64,
-        "paymentProcessorFeeInHostCurrency": -26,
-        "platformFeeInHostCurrency": -5,
-        "subscription": {"__typename": "Subscription", "interval": "month"},
-        "type": "CREDIT",
-    }
-
-    contribution = opencollective.import_transaction_as_contribution(
-        transaction_payload, collective="funkwhale"
-    )
-
-    contributor = contribution.contributor
-
-    author_metadata = transaction_payload["fromCollective"].copy()
-    author_metadata["web_url"] = f"https://opencollective.com/{author_metadata['slug']}"
-
-    assert contributor.name == transaction_payload["fromCollective"]["name"]
-    assert contributor.username == transaction_payload["fromCollective"]["slug"]
-    assert contributor.metadata == {"opencollective": author_metadata}
-
-    assert contribution.summary == transaction_payload["description"]
-    assert contribution.type == "donation"
-    assert contribution.creation_date == datetime.datetime.strptime(
-        transaction_payload["createdAt"], opencollective.DATE_FORMAT
-    )
-    assert contribution.import_date == now
-    assert contribution.is_visible is True
-    assert contribution.external_id == transaction_payload["id"]
-    assert contribution.url is None
-
-    expected_metadata = transaction_payload.copy()
-    expected_metadata.update(
-        {
-            "id": transaction_payload["id"],
-            "amount": transaction_payload["amount"],
-            "currency": transaction_payload["currency"],
-            "collective": "funkwhale",
-            "project_url": f"https://opencollective.com/funkwhale",
-            "subscription": transaction_payload["subscription"],
-        }
-    )
-    assert contribution.metadata == expected_metadata
-
-
-def test_import_contributor_create(db):
-    payload = {
-        "__typename": "User",
-        "id": 22538,
-        "image": "https://www.gravatar.com/avatar/1bf34eec3e0e8a1b6a818103ee6619e1?default=404",
-        "name": "Alice",
-        "path": "/alice",
-        "slug": "alice",
-    }
-
-    contributor = opencollective.import_contributor(payload)
-
-    payload["web_url"] = f"https://opencollective.com/{payload['slug']}"
-
-    assert contributor.name == payload["name"]
-    assert contributor.username == payload["slug"]
-    assert contributor.metadata == {"opencollective": payload}
-
-
-def test_import_contributor_update_metadata(factories):
-    existing = factories.Contributor(username="Alice42", metadata={"hello": "world"})
-    payload = {
-        "__typename": "User",
-        "id": 22538,
-        "image": "https://www.gravatar.com/avatar/1bf34eec3e0e8a1b6a818103ee6619e1?default=404",
-        "name": "Alice",
-        "path": "/alice",
-        "slug": "alice42",
-    }
-
-    contributor = opencollective.import_contributor(payload)
-    payload["web_url"] = f"https://opencollective.com/{payload['slug']}"
-
-    assert contributor == existing
-    assert contributor.name == existing.name
-    assert contributor.username == existing.username
-    assert contributor.metadata == {"opencollective": payload, "hello": "world"}
diff --git a/tmp_gitlab.py b/tmp_gitlab.py
deleted file mode 100644
index 40986477240537c139793c034ba52584995a89c4..0000000000000000000000000000000000000000
--- a/tmp_gitlab.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from contributions.sources import gitlab
-
-
-def retrieve_issues(gitlab_url, project_id):
-    base_url = f"{gitlab_url}/api/v4/projects/{project_id}/issues"
-    url = f"{base_url}?per_page=100"
-    next_page = url
-    while next_page:
-        issues, next_page = gitlab.retrieve_issue_page(next_page)
-        for i in issues:
-            i["_links"] = {"self": f"{base_url}/{i['iid']}"}
-            yield i
-
-
-gitlab_url = "https://code.eliotberriot.com"
-project_id = 17
-project_name = "funkwhale/funkwhale"
-
-for i, issue in enumerate(retrieve_issues(gitlab_url, project_id)):
-    print("Importing issue in database", issue["iid"], issue["title"])
-    gitlab.import_issue_as_contribution(issue, project_name)
diff --git a/tmp_oc.py b/tmp_oc.py
deleted file mode 100644
index 1fd6fe497f07fd4f7d46ba831fd7edef924b2f59..0000000000000000000000000000000000000000
--- a/tmp_oc.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from contributions.sources import opencollective
-
-
-def retrieve_transactions(collective_id):
-    per_page = 50
-    offset = 0
-    while True:
-        transactions = opencollective.retrieve_transactions(
-            collective_id, limit=per_page, offset=offset
-        )
-        for t in transactions:
-            yield t
-        if len(transaction) < per_page:  # last page
-            break
-
-
-collective_id = 18778
-collective_slug = "funkwhale"
-
-for i, transaction in enumerate(retrieve_transactions(collective_id)):
-    print(
-        "Importing contribution in database",
-        transaction["id"],
-        transaction["description"],
-    )
-    opencollective.import_transaction_as_contribution(transaction, collective_slug)
diff --git a/front/yarn.lock b/yarn.lock
similarity index 100%
rename from front/yarn.lock
rename to yarn.lock