commit 7ba937ef662d89b73a5f6369fa0cc5fb4daf095b
Author: Matthew Dillon <mrdillon@alaska.edu>
Date:   Tue Jan 19 15:10:09 2016 -0700

    INITIAL

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c89e0f5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+venv
+*.py[cod]
+*.pyc
+__pycache__
diff --git a/AUTHORS.txt b/AUTHORS.txt
new file mode 100644
index 0000000..b85dee8
--- /dev/null
+++ b/AUTHORS.txt
@@ -0,0 +1,2 @@
+Andre Breton <insightdd@gmail.com>
+Matthew Ryan Dillon <matthewrdillon@gmail.com>
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..b3f1b8c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2013-2016 CCDB Authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7526f8c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,25 @@
+# CCDB
+
+A collections and contaminants database.
+
+## Development Setup
+
+    $ pyvenv venv
+    $ source venv/bin/activate
+    $ pip install -r requirements/local.txt
+    $ createdb tucotuco
+    $ python manage.py migrate
+    $ python manage.py runserver
+
+## 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 a **superuser account**, use this command::
+
+    $ python manage.py createsuperuser
diff --git a/ccdb/__init__.py b/ccdb/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/ccdb/contrib/__init__.py b/ccdb/contrib/__init__.py
new file mode 100644
index 0000000..40a96af
--- /dev/null
+++ b/ccdb/contrib/__init__.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
diff --git a/ccdb/contrib/sites/__init__.py b/ccdb/contrib/sites/__init__.py
new file mode 100644
index 0000000..40a96af
--- /dev/null
+++ b/ccdb/contrib/sites/__init__.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
diff --git a/ccdb/contrib/sites/migrations/0001_initial.py b/ccdb/contrib/sites/migrations/0001_initial.py
new file mode 100644
index 0000000..555d02c
--- /dev/null
+++ b/ccdb/contrib/sites/migrations/0001_initial.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import django.contrib.sites.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Site',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
+                ('domain', models.CharField(verbose_name='domain name', max_length=100, validators=[django.contrib.sites.models._simple_domain_name_validator])),
+                ('name', models.CharField(verbose_name='display name', max_length=50)),
+            ],
+            options={
+                'verbose_name_plural': 'sites',
+                'verbose_name': 'site',
+                'db_table': 'django_site',
+                'ordering': ('domain',),
+            },
+            managers=[
+                (b'objects', django.contrib.sites.models.SiteManager()),
+            ],
+        ),
+    ]
diff --git a/ccdb/contrib/sites/migrations/0002_set_site_domain_and_name.py b/ccdb/contrib/sites/migrations/0002_set_site_domain_and_name.py
new file mode 100644
index 0000000..aea3458
--- /dev/null
+++ b/ccdb/contrib/sites/migrations/0002_set_site_domain_and_name.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations
+
+
+def update_site_forward(apps, schema_editor):
+    """Set site domain and name."""
+    Site = apps.get_model("sites", "Site")
+    Site.objects.update_or_create(
+        id=settings.SITE_ID,
+        defaults={
+            "domain": "ccdb.info",
+            "name": "ccdb"
+        }
+    )
+
+
+def update_site_backward(apps, schema_editor):
+    """Revert site domain and name to default."""
+    Site = apps.get_model("sites", "Site")
+    Site.objects.update_or_create(
+        id=settings.SITE_ID,
+        defaults={
+            "domain": "example.com",
+            "name": "example.com"
+        }
+    )
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('sites', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.RunPython(update_site_forward, update_site_backward),
+    ]
diff --git a/ccdb/contrib/sites/migrations/0003_auto_20151221_2141.py b/ccdb/contrib/sites/migrations/0003_auto_20151221_2141.py
new file mode 100644
index 0000000..832c4ad
--- /dev/null
+++ b/ccdb/contrib/sites/migrations/0003_auto_20151221_2141.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.contrib.sites.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('sites', '0002_set_site_domain_and_name'),
+    ]
+
+    operations = [
+        migrations.AlterModelManagers(
+            name='site',
+            managers=[
+                ('objects', django.contrib.sites.models.SiteManager()),
+            ],
+        ),
+    ]
diff --git a/ccdb/contrib/sites/migrations/__init__.py b/ccdb/contrib/sites/migrations/__init__.py
new file mode 100644
index 0000000..40a96af
--- /dev/null
+++ b/ccdb/contrib/sites/migrations/__init__.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
diff --git a/ccdb/static/css/project.css b/ccdb/static/css/project.css
new file mode 100644
index 0000000..f24ff66
--- /dev/null
+++ b/ccdb/static/css/project.css
@@ -0,0 +1,22 @@
+.alert-debug {
+  background-color: #fff;
+  border-color: #d6e9c6;
+  color: #000; }
+
+.alert-error {
+  background-color: #f2dede;
+  border-color: #eed3d7;
+  color: #b94a48; }
+
+@media (max-width: 47.9em) {
+  .navbar-nav .nav-item {
+    display: inline-block;
+    float: none;
+    width: 100%; }
+  .navbar-nav .nav-item + .nav-item {
+    margin-left: 0; }
+  .nav.navbar-nav.pull-right {
+    float: none !important; } }
+
+[hidden][style="display: block;"] {
+  display: block !important; }
diff --git a/ccdb/static/fonts/.gitkeep b/ccdb/static/fonts/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/ccdb/static/images/favicon.ico b/ccdb/static/images/favicon.ico
new file mode 100644
index 0000000..e1c1dd1
Binary files /dev/null and b/ccdb/static/images/favicon.ico differ
diff --git a/ccdb/static/js/project.js b/ccdb/static/js/project.js
new file mode 100644
index 0000000..d26d23b
--- /dev/null
+++ b/ccdb/static/js/project.js
@@ -0,0 +1 @@
+/* Project specific Javascript goes here. */
diff --git a/ccdb/static/sass/project.scss b/ccdb/static/sass/project.scss
new file mode 100644
index 0000000..37c69e4
--- /dev/null
+++ b/ccdb/static/sass/project.scss
@@ -0,0 +1,51 @@
+// project specific CSS goes here
+
+// Alert colors
+
+$white: #fff;
+$mint-green: #d6e9c6;
+$black: #000;
+$pink: #f2dede;
+$dark-pink: #eed3d7;
+$red: #b94a48;
+
+// bootstrap alert CSS, translated to the django-standard levels of
+// debug, info, success, warning, error
+
+.alert-debug {
+  background-color: $white;
+  border-color: $mint-green;
+  color: $black;
+}
+
+.alert-error {
+  background-color: $pink;
+  border-color: $dark-pink;
+  color: $red;
+}
+
+// This is a fix for the bootstrap4 alpha release
+
+@media (max-width: 47.9em) {
+  .navbar-nav .nav-item {
+    display: inline-block;
+    float: none;
+    width: 100%;
+  }
+
+  .navbar-nav .nav-item + .nav-item {
+    margin-left: 0;
+  }
+
+  .nav.navbar-nav.pull-right {
+    float: none !important;
+  }
+}
+
+// Display django-debug-toolbar.
+// See https://github.com/django-debug-toolbar/django-debug-toolbar/issues/742
+// and https://github.com/pydanny/cookiecutter-django/issues/317
+
+[hidden][style="display: block;"] {
+  display: block !important;
+}
diff --git a/ccdb/templates/404.html b/ccdb/templates/404.html
new file mode 100644
index 0000000..b9cb608
--- /dev/null
+++ b/ccdb/templates/404.html
@@ -0,0 +1,9 @@
+{% extends "base.html" %}
+
+{% block title %}Page Not found{% endblock %}
+
+{% block content %}
+<h1>Page Not found</h1>
+
+<p>This is not the page you were looking for.</p>
+{% endblock content %}
diff --git a/ccdb/templates/500.html b/ccdb/templates/500.html
new file mode 100644
index 0000000..919cf1c
--- /dev/null
+++ b/ccdb/templates/500.html
@@ -0,0 +1,14 @@
+{% extends "base.html" %}
+
+{% block title %}Server Error{% endblock %}
+
+{% block content %}
+<h1>Error</h1>
+
+<h3>Sorry about that, it looks like something went wrong.</h3>
+
+<p>
+  We track these errors automatically, but if the problem persists feel free
+  to contact us. In the meantime, try refreshing.
+</p>
+{% endblock content %}
diff --git a/ccdb/templates/account/base.html b/ccdb/templates/account/base.html
new file mode 100644
index 0000000..4c86ad8
--- /dev/null
+++ b/ccdb/templates/account/base.html
@@ -0,0 +1,6 @@
+{% extends "base.html" %}
+
+{% block title %}
+  {% block head_title %}
+  {% endblock head_title %}
+{% endblock title %}
diff --git a/ccdb/templates/account/email.html b/ccdb/templates/account/email.html
new file mode 100644
index 0000000..490ea43
--- /dev/null
+++ b/ccdb/templates/account/email.html
@@ -0,0 +1,76 @@
+{% extends "account/base.html" %}
+{% block navbar_class-users:detail %}active{% endblock %}
+
+{% load i18n %}
+{% load crispy_forms_tags %}
+
+{% block head_title %}{% trans "Account" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+    <h2>{% trans "E-mail Addresses" %}</h2>
+    {% if user.emailaddress_set.all %}
+      <p>{% trans 'The following e-mail addresses are associated with your account:' %}</p>
+      <form action="{% url 'account_email' %}" class="email_list" method="post">
+        {% csrf_token %}
+        <fieldset class="blockLabels">
+          {% for emailaddress in user.emailaddress_set.all %}
+            <div class="ctrlHolder">
+              <label for="email_radio_{{ forloop.counter }}" class="{% if emailaddress.primary %}primary_email{% endif %}">
+                <input id="email_radio_{{ forloop.counter }}" type="radio" name="email" {% if emailaddress.primary %}checked="checked"{% endif %} value="{{ emailaddress.email }}"/>
+                {{ emailaddress.email }}
+                {% if emailaddress.verified %}
+                  <span class="verified">{% trans "Verified" %}</span>
+                {% else %}
+                  <span class="unverified">{% trans "Unverified" %}</span>
+                {% endif %}
+                {% if emailaddress.primary %}
+                  <span class="primary">{% trans "Primary" %}</span>
+                {% endif %}
+              </label>
+            </div>
+          {% endfor %}
+
+          <div class="btn-group" role="group">
+            <input class="btn btn-primary" type="submit" value="{% trans 'Make Primary' %}" name="action_primary" />
+            <input class="btn btn-success" type="submit" value="{% trans 'Re-send Verification' %}" name="action_send" />
+            <input class="btn btn-danger" type="submit" value="{% trans 'Remove' %}" name="action_remove" />
+          </div>
+        </fieldset>
+      </form>
+    {% else %}
+      <p>
+        <strong>{% trans 'Warning:'%}</strong>
+        {% blocktrans %}
+          You currently do not have any e-mail address set up. You should
+          really add an e-mail address so you can receive notifications,
+          reset your password, etc.
+        {% endblocktrans %}
+      </p>
+    {% endif %}
+    <h2>{% trans "Add E-mail Address" %}</h2>
+    <form method="post" action="." class="add_email">
+      {% csrf_token %}
+      {{ form|crispy }}
+      <button class="btn btn-primary" name="action_add" type="submit">{% trans "Add E-mail" %}</button>
+    </form>
+  </div>
+</div>
+{% endblock %}
+
+{% block extra_body %}
+<script type="text/javascript">
+  (function() {
+    var message = "{% trans 'Do you really want to remove the selected e-mail address?' %}";
+    var actions = document.getElementsByName('action_remove');
+    if (actions.length) {
+      actions[0].addEventListener("click", function(e) {
+        if (! confirm(message)) {
+          e.preventDefault();
+        }
+      });
+    }
+  })();
+</script>
+{% endblock %}
diff --git a/ccdb/templates/account/email_confirm.html b/ccdb/templates/account/email_confirm.html
new file mode 100644
index 0000000..117f856
--- /dev/null
+++ b/ccdb/templates/account/email_confirm.html
@@ -0,0 +1,35 @@
+{% extends "account/base.html" %}
+
+{% load i18n %}
+{% load account %}
+
+{% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-xs-12">
+    <h2>{% trans "Confirm E-mail Address" %}</h2>
+      {% if confirmation %}
+        {% user_display confirmation.email_address.user as user_display %}
+        <p>
+          {% blocktrans with confirmation.email_address.email as email %}
+            Please confirm that <a href="mailto:{{ email }}">{{ email }}</a>
+            is an e-mail address for user {{ user_display }}.
+          {% endblocktrans %}
+        </p>
+        <form method="post" action="{% url 'account_confirm_email' confirmation.key %}">
+          {% csrf_token %}
+          <input class="btn btn-primary" type="submit" value="{% trans 'Confirm' %}" />
+        </form>
+      {% else %}
+        {% url 'account_email' as email_url %}
+        <p>
+          {% blocktrans %}
+            This e-mail confirmation link expired or is invalid. Please
+            <a href="{{ email_url }}">issue a new e-mail confirmation request</a>.
+          {% endblocktrans %}
+        </p>
+      {% endif %}
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/email_confirmed.html b/ccdb/templates/account/email_confirmed.html
new file mode 100644
index 0000000..ed282f9
--- /dev/null
+++ b/ccdb/templates/account/email_confirmed.html
@@ -0,0 +1,21 @@
+{% extends "account/base.html" %}
+
+{% load i18n %}
+{% load account %}
+
+{% block head_title %}{% trans "Confirm E-mail Address" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-xs-12">
+      <h2>{% trans "Confirm E-mail Address" %}</h2>
+      {% user_display email_address.user as user_display %}
+      <p>
+        {% blocktrans with email_address.email as email %}
+          You have confirmed that <a href="mailto:{{ email }}">{{ email }}</a>
+          is an e-mail address for user {{ user_display }}.
+        {% endblocktrans %}
+      </p>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/login.html b/ccdb/templates/account/login.html
new file mode 100644
index 0000000..4979147
--- /dev/null
+++ b/ccdb/templates/account/login.html
@@ -0,0 +1,25 @@
+{% extends "account/base.html" %}
+{% block navbar_class-account_login %}active{% endblock %}
+
+{% load i18n %}
+{% load account %}
+{% load crispy_forms_tags %}
+
+{% block head_title %}{% trans "Sign In" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+    <h2>{% trans "Sign In" %}</h2>
+    <form class="login" method="POST" action="{% url 'account_login' %}">
+      {% csrf_token %}
+      {{ form|crispy }}
+      {% if redirect_field_value %}
+        <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
+      {% endif %}
+      <button id="sign-in-button" class="btn btn-primary" type="submit">{% trans "Sign In" %}</button>
+      <a class="button secondaryAction" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a>
+    </form>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/logout.html b/ccdb/templates/account/logout.html
new file mode 100644
index 0000000..b55404b
--- /dev/null
+++ b/ccdb/templates/account/logout.html
@@ -0,0 +1,22 @@
+{% extends "account/base.html" %}
+{% block navbar_class-account_logout %}active{% endblock %}
+
+{% load i18n %}
+
+{% block head_title %}{% trans "Sign Out" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+    <h2>{% trans "Sign Out" %}</h2>
+    <p>{% trans 'Are you sure you want to sign out?' %}</p>
+    <form method="post" action="{% url 'account_logout' %}">
+      {% csrf_token %}
+      {% if redirect_field_value %}
+        <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
+      {% endif %}
+      <button class="btn btn-danger" type="submit">{% trans 'Sign Out' %}</button>
+    </form>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/password_change.html b/ccdb/templates/account/password_change.html
new file mode 100644
index 0000000..ee373bb
--- /dev/null
+++ b/ccdb/templates/account/password_change.html
@@ -0,0 +1,18 @@
+{% extends "account/base.html" %}
+
+{% load i18n %}
+{% load crispy_forms_tags %}
+{% block head_title %}{% trans "Change Password" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+    <h2>{% trans "Change Password" %}</h2>
+    <form method="POST" action="./" class="password_change">
+      {% csrf_token %}
+      {{ form|crispy }}
+      <button class="btn btn-primary" type="submit" name="action">{% trans "Change Password" %}</button>
+    </form>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/password_reset.html b/ccdb/templates/account/password_reset.html
new file mode 100644
index 0000000..57b8c6d
--- /dev/null
+++ b/ccdb/templates/account/password_reset.html
@@ -0,0 +1,38 @@
+{% extends "account/base.html" %}
+
+{% load i18n %}
+{% load account %}
+{% load crispy_forms_tags %}
+
+{% block head_title %}{% trans "Password Reset" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+      <h2>{% trans "Password Reset" %}</h2>
+      {% if user.is_authenticated %}
+        {% include "account/snippets/already_logged_in.html" %}
+      {% endif %}
+      <p>
+        {% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}
+      </p>
+      <form method="POST" action="./" class="password_reset">
+        {% csrf_token %}
+        {{ form|crispy }}
+        <button class="btn btn-primary" type="submit">{% trans "Reset My Password" %}</button>
+      </form>
+      <p>
+        {% blocktrans %}
+          Please contact us if you have any trouble resetting your password.
+        {% endblocktrans %}
+      </p>
+  </div>
+</div>
+{% endblock %}
+
+{% block javascript %}
+{{ block.super }}
+<script>
+  $("#id_email").focus();
+</script>
+{% endblock javascript %}
diff --git a/ccdb/templates/account/password_reset_done.html b/ccdb/templates/account/password_reset_done.html
new file mode 100644
index 0000000..3835608
--- /dev/null
+++ b/ccdb/templates/account/password_reset_done.html
@@ -0,0 +1,23 @@
+{% extends "account/base.html" %}
+
+{% load i18n %}
+{% load account %}
+
+{% block head_title %}{% trans "Password Reset" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-xs-12">
+    <h2>{% trans "Password Reset" %}</h2>
+      {% if user.is_authenticated %}
+        {% include "account/snippets/already_logged_in.html" %}
+      {% endif %}
+      <p>
+        {% blocktrans %}
+          We have sent you an e-mail. Please contact us if you do not
+          receive it within a few minutes.
+        {% endblocktrans %}
+      </p>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/password_reset_from_key.html b/ccdb/templates/account/password_reset_from_key.html
new file mode 100644
index 0000000..94a2af6
--- /dev/null
+++ b/ccdb/templates/account/password_reset_from_key.html
@@ -0,0 +1,40 @@
+{% extends "account/base.html" %}
+
+{% load i18n %}
+{% load crispy_forms_tags %}
+
+{% block head_title %}{% trans "Change Password" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-xs-12">
+    <h2>
+      {% if token_fail %}
+        {% trans "Bad Token" %}
+      {% else %}
+        {% trans "Change Password" %}
+      {% endif %}
+    </h2>
+    {% if token_fail %}
+      {% url 'account_reset_password' as passwd_reset_url %}
+      <p>
+        {% blocktrans %}
+          The password reset link was invalid, possibly because it has already
+          been used.  Please request a <a href="{{ passwd_reset_url }}">new
+          password reset</a>.
+        {% endblocktrans %}
+      </p>
+    {% else %}
+      {% if form %}
+        <form method="POST" action="./">
+          {% csrf_token %}
+          {{ form|crispy }}
+          <button class="btn btn-primary" type="submit" name="action">{% trans "change password" %}</button>
+        </form>
+      {% else %}
+        <p>{% trans 'Your password is now changed.' %}</p>
+      {% endif %}
+    {% endif %}
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/password_reset_from_key_done.html b/ccdb/templates/account/password_reset_from_key_done.html
new file mode 100644
index 0000000..8440069
--- /dev/null
+++ b/ccdb/templates/account/password_reset_from_key_done.html
@@ -0,0 +1,13 @@
+{% extends "account/base.html" %}
+
+{% load i18n %}
+{% block head_title %}{% trans "Change Password" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+      <h2>{% trans "Change Password" %}</h2>
+      <p>{% trans 'Your password is now changed.' %}</p>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/password_set.html b/ccdb/templates/account/password_set.html
new file mode 100644
index 0000000..d5c39f6
--- /dev/null
+++ b/ccdb/templates/account/password_set.html
@@ -0,0 +1,19 @@
+
+{% extends "account/base.html" %}
+
+{% load i18n crispy_forms_tags %}
+
+{% block head_title %}{% trans "Set Password" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+    <h2>{% trans "Set Password" %}</h2>
+    <form method="POST" action="./" class="password_set">
+      {% csrf_token %}
+      {{ form|crispy }}
+      <input type="submit" name="action" value="{% trans "Set Password" %}"/>
+    </form>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/signup.html b/ccdb/templates/account/signup.html
new file mode 100644
index 0000000..217df06
--- /dev/null
+++ b/ccdb/templates/account/signup.html
@@ -0,0 +1,29 @@
+{% extends "account/base.html" %}
+{% block navbar_class-account_signup %}active{% endblock %}
+
+{% load i18n %}
+{% load crispy_forms_tags %}
+
+{% block title %}{% trans "Signup" %}{% endblock title %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+    <h1>{% trans "Sign Up" %}</h1>
+    <p>
+      {% blocktrans %}
+        Already have an account? Then please
+        <a href="{{ login_url }}">sign in</a>.
+      {% endblocktrans %}
+    </p>
+    <form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}">
+      {% csrf_token %}
+      {{ form|crispy }}
+      {% if redirect_field_value %}
+        <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
+      {% endif %}
+      <button id="sign-up-button" class="btn btn-primary" type="submit">{% trans "Sign Up" %}</button>
+    </form>
+  </div>
+</div>
+{% endblock content %}
diff --git a/ccdb/templates/account/signup_closed.html b/ccdb/templates/account/signup_closed.html
new file mode 100644
index 0000000..c18daf7
--- /dev/null
+++ b/ccdb/templates/account/signup_closed.html
@@ -0,0 +1,14 @@
+{% extends "account/base.html" %}
+
+{% load i18n %}
+
+{% block head_title %}{% trans "Sign Up Closed" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+    <h2>{% trans "Sign Up Closed" %}</h2>
+    <p>{% trans "We are sorry, but the sign up is currently closed." %}</p>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/verification_sent.html b/ccdb/templates/account/verification_sent.html
new file mode 100644
index 0000000..b23e4c8
--- /dev/null
+++ b/ccdb/templates/account/verification_sent.html
@@ -0,0 +1,20 @@
+{% extends "account/base.html" %}
+
+{% load i18n %}
+
+{% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+    <h2>{% trans "Verify Your E-mail Address" %}</h2>
+    <p>
+      {% blocktrans %}
+        We have sent an e-mail to <a href="mailto:{{ email }}">{{ email }}</a>
+        for verification. Follow the link provided to finalize the signup
+        process. Please contact us if you do not receive it within a few minutes.
+      {% endblocktrans %}
+    </p>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/account/verified_email_required.html b/ccdb/templates/account/verified_email_required.html
new file mode 100644
index 0000000..d844a4a
--- /dev/null
+++ b/ccdb/templates/account/verified_email_required.html
@@ -0,0 +1,34 @@
+{% extends "account/base.html" %}
+
+{% load i18n %}
+
+{% block head_title %}{% trans "Verify Your E-mail Address" %}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-md-5">
+    <h2>{% trans "Verify Your E-mail Address" %}</h2>
+    {% url 'account_email' as email_url %}
+    <p>
+      {% blocktrans %}
+        This part of the site requires us to verify that you are who you claim
+        to be. For this purpose, we require that you verify ownership of your
+        e-mail address.
+      {% endblocktrans %}
+    </p>
+    <p>
+      {% blocktrans %}
+        We have sent an e-mail to you for verification. Please click on the
+        link inside this e-mail. Please contact us if you do not receive it
+        within a few minutes.
+      {% endblocktrans %}
+    </p>
+    <p>
+      {% blocktrans %}
+        <strong>Note:</strong> you can still <a href="{{ email_url }}">change
+        your e-mail address</a>.
+      {% endblocktrans %}
+    </p>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/base.html b/ccdb/templates/base.html
new file mode 100644
index 0000000..d59ea9d
--- /dev/null
+++ b/ccdb/templates/base.html
@@ -0,0 +1,101 @@
+{% load staticfiles %}
+{% load i18n %}
+
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>{% block title %}CCDB{% endblock title %}</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <meta name="description" content="">
+    <meta name="author" content="">
+
+    <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
+    <!--[if lt IE 9]>
+      <script src="https://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+    <![endif]-->
+
+    {% block css %}
+      <link href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/flatly/bootstrap.min.css" rel="stylesheet" integrity="sha256-sHwgyDk4CGNYom267UJX364ewnY4Bh55d53pxP5WDug= sha512-mkkeSf+MM3dyMWg3k9hcAttl7IVHe2BA1o/5xKLl4kBaP0bih7Mzz/DBy4y6cNZCHtE2tPgYBYH/KtEjOQYKxA==" crossorigin="anonymous">
+      <link href="{% static 'css/project.css' %}" rel="stylesheet">
+    {% endblock %}
+  </head>
+
+  <body>
+    <div>
+      <nav class="navbar navbar-default navbar-static-top">
+        <div class="container-fluid">
+          <div class="navbar-header">
+            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+              <span class="sr-only">Toggle navigation</span>
+              <span class="icon-bar"></span>
+              <span class="icon-bar"></span>
+              <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="{% url 'home' %}">CCDB</a>
+          </div>
+
+          <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+            <ul class="nav navbar-nav">
+              {% if request.user.is_authenticated %}
+                {% comment %}
+                <li class="nav-item {% block navbar_class-projects %}{% endblock %}">
+                  <a class="nav-link" href="{% url 'projects:project_list' %}">
+                    {% trans "Projects" %}
+                  </a>
+                </li>
+                {% endcomment %}
+              {% endif %}
+            </ul>
+            <ul class="nav navbar-nav pull-right">
+              {% if request.user.is_authenticated %}
+                <li class="nav-item {% block navbar_class-users:detail %}{% endblock %}">
+                  <a class="nav-link" href="{% url 'users:detail' request.user.username  %}">
+                    {% trans "My Profile" %}
+                  </a>
+                </li>
+                <li class="nav-item {% block navbar_class-account_logout %}{% endblock %}">
+                  <a class="nav-link" href="{% url 'account_logout' %}">
+                    {% trans "Logout" %}
+                  </a>
+                </li>
+              {% else %}
+                <li class="nav-item {% block navbar_class-account_signup %}{% endblock %}">
+                  <a id="sign-up-link" class="nav-link" href="{% url 'account_signup' %}">
+                    {% trans "Sign Up" %}
+                  </a>
+                </li>
+                <li class="nav-item {% block navbar_class-account_login %}{% endblock %}">
+                  <a id="log-in-link" class="nav-link" href="{% url 'account_login' %}">
+                    {% trans "Log In" %}
+                  </a>
+                </li>
+              {% endif %}
+            </ul>
+          </div>
+        </div>
+      </nav>
+    </div>
+
+    <div class="container">
+      {% if messages %}
+          {% for message in messages %}
+              <div class="alert {% if message.tags %}alert-{{ message.tags }}"{% endif %}>{{ message }}</div>
+          {% endfor %}
+      {% endif %}
+
+      {% block content %}
+        <p>PLACEHOLDER</p>
+      {% endblock content %}
+    </div>
+
+    {% block modal %}{% endblock modal %}
+
+    {% block javascript %}
+      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
+      <script src="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/js/bootstrap.js"></script>
+      <script src="{% static 'js/project.js' %}"></script>
+    {% endblock javascript %}
+  </body>
+</html>
diff --git a/ccdb/templates/django_tables2/table.html b/ccdb/templates/django_tables2/table.html
new file mode 100644
index 0000000..306149d
--- /dev/null
+++ b/ccdb/templates/django_tables2/table.html
@@ -0,0 +1,58 @@
+{% load querystring from django_tables2 %}
+{% load title from django_tables2 %}
+{% load trans blocktrans from i18n %}
+{% load bootstrap3 %}
+
+{% if table.page %}
+  <div class="table-container">
+{% endif %}
+
+{% block table %}
+<table class="table table-striped"{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}>
+  {% block table.thead %}
+  <thead>
+    <tr>
+    {% for column in table.columns %}
+      {% if column.orderable %}
+      <th {{ column.attrs.th.as_html }}><a href="{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}">{{ column.header|title }}</a></th>
+      {% else %}
+      <th {{ column.attrs.th.as_html }}>{{ column.header|title }}</th>
+      {% endif %}
+    {% endfor %}
+    </tr>
+  </thead>
+  {% endblock table.thead %}
+  {% block table.tbody %}
+  <tbody>
+    {% for row in table.page.object_list|default:table.rows %} {# support pagination #}
+    {% block table.tbody.row %}
+    <tr class="{% cycle "odd" "even" %}">
+      {% for column, cell in row.items %}
+        <td {{ column.attrs.td.as_html }}>{{ cell }}</td>
+      {% endfor %}
+    </tr>
+    {% endblock table.tbody.row %}
+    {% empty %}
+    {% if table.empty_text %}
+    {% block table.tbody.empty_text %}
+    <tr><td colspan="{{ table.columns|length }}">{{ table.empty_text }}</td></tr>
+    {% endblock table.tbody.empty_text %}
+    {% endif %}
+    {% endfor %}
+  </tbody>
+  {% endblock table.tbody %}
+  {% block table.tfoot %}
+  <tfoot></tfoot>
+  {% endblock table.tfoot %}
+</table>
+{% endblock table %}
+
+{% if table.page %}
+  {% block pagination %}
+    {% bootstrap_pagination table.page url=request.get_full_path %}
+  {% endblock pagination %}
+{% endif %}
+
+{% if table.page %}
+  </div>
+{% endif %}
diff --git a/ccdb/templates/pages/about.html b/ccdb/templates/pages/about.html
new file mode 100644
index 0000000..241d395
--- /dev/null
+++ b/ccdb/templates/pages/about.html
@@ -0,0 +1,6 @@
+{% extends "base.html" %}
+{% block navbar_class-about %}active{% endblock %}
+
+{% block content %}
+<h1>About</h1>
+{% endblock content %}
diff --git a/ccdb/templates/pages/home.html b/ccdb/templates/pages/home.html
new file mode 100644
index 0000000..7a7e2dd
--- /dev/null
+++ b/ccdb/templates/pages/home.html
@@ -0,0 +1,7 @@
+{% extends "base.html" %}
+
+{% block content %}
+<h1>CCDB</h1>
+
+<p>This page will have overview data.</p>
+{% endblock content %}
diff --git a/ccdb/templates/users/user_detail.html b/ccdb/templates/users/user_detail.html
new file mode 100644
index 0000000..f374b9f
--- /dev/null
+++ b/ccdb/templates/users/user_detail.html
@@ -0,0 +1,28 @@
+{% extends "base.html" %}
+{% block navbar_class-users:detail %}active{% endblock %}
+{% load static %}
+
+{% block title %}User: {{ object.username }}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-sm-12">
+    <h1>{{ object.username }}</h1>
+    {% if object.name %}
+      <p>{{ object.name }}</p>
+    {% endif %}
+  </div>
+</div>
+
+{% if object == request.user %}
+<!-- Action buttons -->
+<div class="row">
+  <div class="col-sm-12 ">
+    <a class="btn btn-primary" href="{% url 'users:update' username=request.user.username %}">My Info</a>
+    <a class="btn btn-primary" href="{% url 'account_email' %}">E-Mail</a>
+    <!-- Your Stuff: Custom user template urls -->
+  </div>
+</div>
+<!-- End Action buttons -->
+{% endif %}
+{% endblock content %}
diff --git a/ccdb/templates/users/user_form.html b/ccdb/templates/users/user_form.html
new file mode 100644
index 0000000..46842dc
--- /dev/null
+++ b/ccdb/templates/users/user_form.html
@@ -0,0 +1,19 @@
+{% extends "base.html" %}
+{% block navbar_class-users:detail %}active{% endblock %}
+{% load crispy_forms_tags %}
+{% load static %}
+
+{% block title %}{{ user.username }}{% endblock %}
+
+{% block content %}
+<div class="row">
+  <div class="col-sm-12">
+    <h1>{{ user.username }}</h1>
+    <form class="form" method="POST" action="">
+      {% csrf_token %}
+      {{ form|crispy }}
+      <input class="btn btn-primary" type="submit" value="Submit" />
+    </form>
+  </div>
+</div>
+{% endblock %}
diff --git a/ccdb/templates/users/user_list.html b/ccdb/templates/users/user_list.html
new file mode 100644
index 0000000..6e510ed
--- /dev/null
+++ b/ccdb/templates/users/user_list.html
@@ -0,0 +1,14 @@
+{% extends "base.html" %}
+{% load static %}{% load i18n %}
+{% block title %}Members{% endblock %}
+
+{% block content %}
+<h2>Users</h2>
+<div class="list-group">
+  {% for user in user_list %}
+    <a href="{% url 'users:detail' user.username %}" class="list-group-item">
+      <h4 class="list-group-item-heading">{{ user.username }}</h4>
+    </a>
+  {% endfor %}
+</div>
+{% endblock content %}
diff --git a/ccdb/users/__init__.py b/ccdb/users/__init__.py
new file mode 100644
index 0000000..40a96af
--- /dev/null
+++ b/ccdb/users/__init__.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
diff --git a/ccdb/users/admin.py b/ccdb/users/admin.py
new file mode 100644
index 0000000..51a6ebc
--- /dev/null
+++ b/ccdb/users/admin.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
+
+from django import forms
+from django.contrib import admin
+from django.contrib.auth.admin import UserAdmin as AuthUserAdmin
+from django.contrib.auth.forms import UserChangeForm, UserCreationForm
+
+from .models import User
+
+
+class MyUserChangeForm(UserChangeForm):
+    class Meta(UserChangeForm.Meta):
+        model = User
+
+
+class MyUserCreationForm(UserCreationForm):
+    error_message = UserCreationForm.error_messages.update({
+        'duplicate_username': 'This username has already been taken.'
+    })
+
+    class Meta(UserCreationForm.Meta):
+        model = User
+
+    def clean_username(self):
+        username = self.cleaned_data["username"]
+        try:
+            User.objects.get(username=username)
+        except User.DoesNotExist:
+            return username
+        raise forms.ValidationError(self.error_messages['duplicate_username'])
+
+
+@admin.register(User)
+class UserAdmin(AuthUserAdmin):
+    form = MyUserChangeForm
+    add_form = MyUserCreationForm
diff --git a/ccdb/users/middleware.py b/ccdb/users/middleware.py
new file mode 100644
index 0000000..e1e72a6
--- /dev/null
+++ b/ccdb/users/middleware.py
@@ -0,0 +1,13 @@
+import pytz
+
+from django.utils import timezone
+
+
+class TimezoneMiddleware(object):
+    def process_request(self, request):
+        if not request.user.is_anonymous():
+            tzname = request.user.timezone
+            if tzname:
+                timezone.activate(pytz.timezone(tzname))
+            else:
+                timezone.deactivate()
diff --git a/ccdb/users/migrations/0001_initial.py b/ccdb/users/migrations/0001_initial.py
new file mode 100644
index 0000000..8327d28
--- /dev/null
+++ b/ccdb/users/migrations/0001_initial.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import django.utils.timezone
+import django.contrib.auth.models
+import django.core.validators
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('auth', '0006_require_contenttypes_0002'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='User',
+            fields=[
+                ('id', models.AutoField(primary_key=True, verbose_name='ID', serialize=False, auto_created=True)),
+                ('password', models.CharField(max_length=128, verbose_name='password')),
+                ('last_login', models.DateTimeField(null=True, verbose_name='last login', blank=True)),
+                ('is_superuser', models.BooleanField(help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status', default=False)),
+                ('username', models.CharField(max_length=30, validators=[django.core.validators.RegexValidator('^[\\w.@+-]+$', 'Enter a valid username. This value may contain only letters, numbers and @/./+/-/_ characters.', 'invalid')], verbose_name='username', error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True)),
+                ('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)),
+                ('last_name', models.CharField(max_length=30, verbose_name='last name', blank=True)),
+                ('email', models.EmailField(max_length=254, verbose_name='email address', blank=True)),
+                ('is_staff', models.BooleanField(help_text='Designates whether the user can log into this admin site.', verbose_name='staff status', default=False)),
+                ('is_active', models.BooleanField(help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active', default=True)),
+                ('date_joined', models.DateTimeField(verbose_name='date joined', default=django.utils.timezone.now)),
+                ('groups', models.ManyToManyField(related_name='user_set', blank=True, verbose_name='groups', to='auth.Group', help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_query_name='user')),
+                ('user_permissions', models.ManyToManyField(related_name='user_set', blank=True, verbose_name='user permissions', to='auth.Permission', help_text='Specific permissions for this user.', related_query_name='user')),
+                ('name', models.CharField(max_length=255, verbose_name='Name of User', blank=True)),
+            ],
+            options={
+                'verbose_name': 'user',
+                'abstract': False,
+                'verbose_name_plural': 'users',
+            },
+            managers=[
+                (b'objects', django.contrib.auth.models.UserManager()),
+            ],
+        ),
+    ]
diff --git a/ccdb/users/migrations/0002_timezone.py b/ccdb/users/migrations/0002_timezone.py
new file mode 100644
index 0000000..dbb7ae6
--- /dev/null
+++ b/ccdb/users/migrations/0002_timezone.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.contrib.auth.models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('users', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterModelManagers(
+            name='user',
+            managers=[
+                ('objects', django.contrib.auth.models.UserManager()),
+            ],
+        ),
+        migrations.AddField(
+            model_name='user',
+            name='timezone',
+            field=models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santa_Isabel', 'America/Santa_Isabel'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Rangoon', 'Asia/Rangoon'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Johnston', 'Pacific/Johnston'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], max_length=255, verbose_name='Current Timezone', default='UTC'),
+        ),
+    ]
diff --git a/ccdb/users/migrations/__init__.py b/ccdb/users/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/ccdb/users/models.py b/ccdb/users/models.py
new file mode 100644
index 0000000..a73b71c
--- /dev/null
+++ b/ccdb/users/models.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from django.contrib.auth.models import AbstractUser
+from django.core.urlresolvers import reverse
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+from django.conf import settings
+
+import pytz
+
+
+class User(AbstractUser):
+    name = models.CharField(_("Name of User"), blank=True, max_length=255)
+    timezone = models.CharField(_("Current Timezone"), max_length=255,
+        default="UTC", choices=[(x, x) for x in pytz.common_timezones],
+        blank=False)
+
+    def __str__(self):
+        return self.username
+
+    def get_absolute_url(self):
+        return reverse('users:detail', kwargs={'username': self.username})
diff --git a/ccdb/users/tests/__init__.py b/ccdb/users/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/ccdb/users/tests/factories.py b/ccdb/users/tests/factories.py
new file mode 100644
index 0000000..e2c967d
--- /dev/null
+++ b/ccdb/users/tests/factories.py
@@ -0,0 +1,11 @@
+import factory
+
+
+class UserFactory(factory.django.DjangoModelFactory):
+    username = factory.Sequence(lambda n: 'user-{0}'.format(n))
+    email = factory.Sequence(lambda n: 'user-{0}@example.com'.format(n))
+    password = factory.PostGenerationMethodCall('set_password', 'password')
+
+    class Meta:
+        model = 'users.User'
+        django_get_or_create = ('username', )
diff --git a/ccdb/users/tests/test_admin.py b/ccdb/users/tests/test_admin.py
new file mode 100644
index 0000000..8faf96a
--- /dev/null
+++ b/ccdb/users/tests/test_admin.py
@@ -0,0 +1,39 @@
+from test_plus.test import TestCase
+
+from ..admin import MyUserCreationForm
+
+
+class TestMyUserCreationForm(TestCase):
+    def setUp(self):
+        self.user = self.make_user()
+
+    def test_clean_username_success(self):
+        # Instantiate the form with a new username
+        form = MyUserCreationForm({
+            'username': 'alamode',
+            'password1': '123456',
+            'password2': '123456',
+        })
+        # Run is_valid() to trigger the validation
+        valid = form.is_valid()
+        self.assertTrue(valid)
+
+        # Run the actual clean_username method
+        username = form.clean_username()
+        self.assertEqual('alamode', username)
+
+    def test_clean_username_false(self):
+        # Instantiate the form with the same username as self.user
+        form = MyUserCreationForm({
+            'username': self.user.username,
+            'password1': '123456',
+            'password2': '123456',
+        })
+        # Run is_valid() to trigger the validation, which is going to fail
+        # because the username is already taken
+        valid = form.is_valid()
+        self.assertFalse(valid)
+
+        # The form.errors dict should contain a single error called 'username'
+        self.assertTrue(len(form.errors) == 1)
+        self.assertTrue('username' in form.errors)
diff --git a/ccdb/users/tests/test_models.py b/ccdb/users/tests/test_models.py
new file mode 100644
index 0000000..c0e4df6
--- /dev/null
+++ b/ccdb/users/tests/test_models.py
@@ -0,0 +1,18 @@
+from test_plus.test import TestCase
+
+
+class TestUser(TestCase):
+    def setUp(self):
+        self.user = self.make_user()
+
+    def test__str__(self):
+        self.assertEqual(
+            self.user.__str__(),
+            "testuser"  # This is the default username for self.make_user()
+        )
+
+    def test_get_absolute_url(self):
+        self.assertEqual(
+            self.user.get_absolute_url(),
+            '/users/testuser/'
+        )
diff --git a/ccdb/users/tests/test_views.py b/ccdb/users/tests/test_views.py
new file mode 100644
index 0000000..587331b
--- /dev/null
+++ b/ccdb/users/tests/test_views.py
@@ -0,0 +1,66 @@
+from django.test import RequestFactory
+
+from test_plus.test import TestCase
+
+from ..views import (
+    UserRedirectView,
+    UserUpdateView
+)
+
+
+class BaseUserTestCase(TestCase):
+    def setUp(self):
+        self.user = self.make_user()
+        self.factory = RequestFactory()
+
+
+class TestUserRedirectView(BaseUserTestCase):
+    def test_get_redirect_url(self):
+        # Instantiate the view directly. Never do this outside a test!
+        view = UserRedirectView()
+        # Generate a fake request
+        request = self.factory.get('/fake-url')
+        # Attach the user to the request
+        request.user = self.user
+        # Attach the request to the view
+        view.request = request
+        # Expect: '/users/testuser/', as that is the default username for
+        #   self.make_user()
+        self.assertEqual(
+            view.get_redirect_url(),
+            '/users/testuser/'
+        )
+
+
+class TestUserUpdateView(BaseUserTestCase):
+    def setUp(self):
+        # call BaseUserTestCase.setUp()
+        super(TestUserUpdateView, self).setUp()
+        # Instantiate the view directly. Never do this outside a test!
+        self.view = UserUpdateView()
+        # Generate a fake request
+        request = self.factory.get('/fake-url')
+        # Attach the user to the request
+        request.user = self.user
+        # Attach the request to the view
+        self.view.request = request
+
+    def test_get_success_url(self):
+        # Expect: '/users/testuser/', as that is the default username for
+        #   self.make_user()
+        self.assertEqual(
+            self.view.get_success_url(),
+            '/users/testuser/'
+        )
+
+    # TODO: write this test
+    # def test_get_redirected(self):
+        # Expect '/users/testuser01/' to redirect, because that isn't the
+        #   currently logged in user
+
+    def test_get_object(self):
+        # Expect: self.user, as that is the request's user object
+        self.assertEqual(
+            self.view.get_object(),
+            self.user
+        )
diff --git a/ccdb/users/urls.py b/ccdb/users/urls.py
new file mode 100644
index 0000000..9ae4347
--- /dev/null
+++ b/ccdb/users/urls.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
+
+from django.conf.urls import url
+
+from . import views
+
+
+urlpatterns = [
+    url(regex=r'^$', view=views.UserListView.as_view(), name='list'),
+    url(regex=r'^redirect/$', view=views.UserRedirectView.as_view(), name='redirect'),
+    url(regex=r'^(?P<username>[\w.@+-]+)/$', view=views.UserDetailView.as_view(), name='detail'),
+    url(regex=r'^(?P<username>[\w.@+-]+)/update/$', view=views.UserUpdateView.as_view(), name='update'),
+]
diff --git a/ccdb/users/views.py b/ccdb/users/views.py
new file mode 100644
index 0000000..73a9dbf
--- /dev/null
+++ b/ccdb/users/views.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import, unicode_literals
+
+from django.core.urlresolvers import reverse
+from django.views.generic import DetailView, ListView, RedirectView, UpdateView
+from django.shortcuts import redirect
+
+from braces.views import LoginRequiredMixin
+
+from .models import User
+
+
+class UserDetailView(LoginRequiredMixin, DetailView):
+    model = User
+    # These next two lines tell the view to index lookups by username
+    slug_field = "username"
+    slug_url_kwarg = "username"
+
+
+class UserRedirectView(LoginRequiredMixin, RedirectView):
+    permanent = False
+
+    def get_redirect_url(self):
+        return reverse("users:detail",
+                       kwargs={"username": self.request.user.username})
+
+
+class UserUpdateView(LoginRequiredMixin, UpdateView):
+    fields = ['name', 'timezone']
+    model = User
+
+    def dispatch(self, request, *args, **kwargs):
+        if request.user.username != kwargs.pop("username", None):
+            return redirect(reverse("users:detail",
+                                    kwargs={"username": request.user.username}))
+        return super(UserUpdateView, self).dispatch(request, *args, **kwargs)
+
+    def get_success_url(self):
+        return reverse("users:detail",
+                       kwargs={"username": self.request.user.username})
+
+    def get_object(self):
+        # Only get the User record for the user making the request
+        return User.objects.get(username=self.request.user.username)
+
+
+class UserListView(LoginRequiredMixin, ListView):
+    model = User
+    # These next two lines tell the view to index lookups by username
+    slug_field = "username"
+    slug_url_kwarg = "username"
diff --git a/config/__init__.py b/config/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/config/settings/__init__.py b/config/settings/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/config/settings/base.py b/config/settings/base.py
new file mode 100644
index 0000000..9dc8b2e
--- /dev/null
+++ b/config/settings/base.py
@@ -0,0 +1,230 @@
+"""
+Django settings for CCDB
+"""
+from __future__ import absolute_import, unicode_literals
+
+from django.utils.translation import ugettext_lazy as _
+
+import environ
+
+ROOT_DIR = environ.Path(__file__) - 3  # (/a/b/myfile.py - 3 = /)
+APPS_DIR = ROOT_DIR.path('ccdb')
+
+env = environ.Env()
+
+# APP CONFIGURATION
+# ------------------------------------------------------------------------------
+DJANGO_APPS = (
+    # Default Django apps:
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+
+    # Admin
+    'django.contrib.admin',
+)
+THIRD_PARTY_APPS = (
+    'crispy_forms',  # Form layouts
+    'allauth',  # registration
+    'allauth.account',  # registration
+    'bootstrap3', # bootstrappin'
+    'django_tables2', # data grids
+)
+
+# Apps specific for this project go here.
+LOCAL_APPS = (
+    'ccdb.users',  # custom users app
+)
+
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
+INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
+
+# MIDDLEWARE CONFIGURATION
+# ------------------------------------------------------------------------------
+MIDDLEWARE_CLASSES = (
+    # Make sure djangosecure.middleware.SecurityMiddleware is listed first
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.locale.LocaleMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    'ccdb.users.middleware.TimezoneMiddleware',
+)
+
+# MIGRATIONS CONFIGURATION
+# ------------------------------------------------------------------------------
+MIGRATION_MODULES = {
+    'sites': 'ccdb.contrib.sites.migrations'
+}
+
+# DEBUG
+# ------------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#debug
+DEBUG = env.bool("DJANGO_DEBUG", False)
+
+# FIXTURE CONFIGURATION
+# ------------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FIXTURE_DIRS
+FIXTURE_DIRS = (
+    str(APPS_DIR.path('fixtures')),
+)
+
+# EMAIL CONFIGURATION
+# ------------------------------------------------------------------------------
+EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND', default='django.core.mail.backends.smtp.EmailBackend')
+
+# MANAGER CONFIGURATION
+# ------------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#admins
+ADMINS = (
+    ("""Matthew Ryan Dillon""", 'matthewrdillon@gmail.com'),
+)
+
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#managers
+MANAGERS = ADMINS
+
+# DATABASE CONFIGURATION
+# ------------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#databases
+DATABASES = {
+    # Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
+    'default': env.db("DATABASE_URL", default="postgres:///ccdbdjango"),
+}
+DATABASES['default']['ATOMIC_REQUESTS'] = True
+
+
+# GENERAL CONFIGURATION
+# ------------------------------------------------------------------------------
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# In a Windows environment this must be set to your system time zone.
+TIME_ZONE = 'UTC'
+
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#language-code
+LANGUAGE_CODE = 'en'
+
+LANGUAGES = (
+  ('en', _('English')),
+)
+
+LOCALE_PATHS = [
+    'locale',
+]
+
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#site-id
+SITE_ID = 1
+
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
+USE_I18N = True
+
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-l10n
+USE_L10N = True
+
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#use-tz
+USE_TZ = True
+
+# TEMPLATE CONFIGURATION
+# ------------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#templates
+TEMPLATES = [
+    {
+        # See: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-TEMPLATES-BACKEND
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
+        'DIRS': [
+            str(APPS_DIR.path('templates')),
+        ],
+        'OPTIONS': {
+            # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-debug
+            'debug': DEBUG,
+            # See: 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',
+            ],
+            # See: 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',
+                'django.core.context_processors.request',
+            ],
+        },
+    },
+]
+
+# See: http://django-crispy-forms.readthedocs.org/en/latest/install.html#template-packs
+CRISPY_TEMPLATE_PACK = 'bootstrap3'
+
+# STATIC FILE CONFIGURATION
+# ------------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-root
+STATIC_ROOT = str(ROOT_DIR('staticfiles'))
+
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
+STATIC_URL = '/static/'
+
+# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
+STATICFILES_DIRS = (
+    str(APPS_DIR.path('static')),
+)
+
+# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders
+STATICFILES_FINDERS = (
+    'django.contrib.staticfiles.finders.FileSystemFinder',
+    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+)
+
+# MEDIA CONFIGURATION
+# ------------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root
+MEDIA_ROOT = str(APPS_DIR('media'))
+
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#media-url
+MEDIA_URL = '/media/'
+
+# URL Configuration
+# ------------------------------------------------------------------------------
+ROOT_URLCONF = 'config.urls'
+
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#wsgi-application
+WSGI_APPLICATION = 'config.wsgi.application'
+
+# AUTHENTICATION CONFIGURATION
+# ------------------------------------------------------------------------------
+AUTHENTICATION_BACKENDS = (
+    'django.contrib.auth.backends.ModelBackend',
+    'allauth.account.auth_backends.AuthenticationBackend',
+)
+
+ACCOUNT_AUTHENTICATION_METHOD = 'username'
+ACCOUNT_EMAIL_REQUIRED = True
+ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
+
+# Custom user app defaults
+# Select the correct user model
+AUTH_USER_MODEL = 'users.User'
+LOGIN_REDIRECT_URL = 'users:redirect'
+LOGIN_URL = 'account_login'
+
+# SLUGLIFIER
+AUTOSLUG_SLUGIFY_FUNCTION = 'slugify.slugify'
+
+
+# Location of root django.contrib.admin URL, use {% url 'admin:index' %}
+ADMIN_URL = r'^admin/'
+
+# Your common stuff: Below this line define 3rd party library settings
diff --git a/config/settings/local.py b/config/settings/local.py
new file mode 100644
index 0000000..cd18f73
--- /dev/null
+++ b/config/settings/local.py
@@ -0,0 +1,48 @@
+'''
+Local settings
+
+- Run in Debug mode
+- Use console backend for emails
+- Add Django Debug Toolbar
+'''
+
+from .base import *  # noqa
+
+# DEBUG
+# ------------------------------------------------------------------------------
+DEBUG = env.bool('DJANGO_DEBUG', default=True)
+TEMPLATES[0]['OPTIONS']['debug'] = DEBUG
+
+# SECRET CONFIGURATION
+# ------------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
+# Note: This key only used for development and testing.
+SECRET_KEY = env("DJANGO_SECRET_KEY", default='t69v7lq5ayk^k_)uyvjvpo(sljrcnbh)&$(rsqqjg-87160@^%')
+
+# Mail settings
+# ------------------------------------------------------------------------------
+EMAIL_HOST = 'localhost'
+EMAIL_PORT = 1025
+EMAIL_BACKEND = env('DJANGO_EMAIL_BACKEND',
+                    default='django.core.mail.backends.console.EmailBackend')
+
+
+# django-debug-toolbar
+# ------------------------------------------------------------------------------
+MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
+INSTALLED_APPS += ('debug_toolbar', )
+
+INTERNAL_IPS = ('127.0.0.1', )
+
+DEBUG_TOOLBAR_CONFIG = {
+    'DISABLE_PANELS': [
+        'debug_toolbar.panels.redirects.RedirectsPanel',
+    ],
+    'SHOW_TEMPLATE_CONTEXT': True,
+}
+
+# TESTING
+# ------------------------------------------------------------------------------
+TEST_RUNNER = 'django.test.runner.DiscoverRunner'
+
+# Your local stuff: Below this line define 3rd party library settings
diff --git a/config/settings/production.py b/config/settings/production.py
new file mode 100644
index 0000000..632c9d6
--- /dev/null
+++ b/config/settings/production.py
@@ -0,0 +1,165 @@
+'''
+Production Configurations
+
+- Use Amazon's S3 for storing static files and uploaded media
+- Use mailgun to send emails
+
+'''
+from __future__ import absolute_import, unicode_literals
+
+from boto.s3.connection import OrdinaryCallingFormat
+from django.utils import six
+
+
+from .base import *  # noqa
+
+# SECRET CONFIGURATION
+# ------------------------------------------------------------------------------
+# See: https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
+# Raises ImproperlyConfigured exception if DJANGO_SECRET_KEY not in os.environ
+SECRET_KEY = env("DJANGO_SECRET_KEY")
+
+# This ensures that Django will be able to detect a secure connection
+# properly on Heroku.
+SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
+
+
+# Make sure djangosecure.middleware.SecurityMiddleware is listed first
+MIDDLEWARE_CLASSES = SECURITY_MIDDLEWARE + MIDDLEWARE_CLASSES
+
+# set this to 60 seconds and then to 518400 when you can prove it works
+SECURE_HSTS_SECONDS = 60
+SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool(
+    "DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True)
+SECURE_FRAME_DENY = env.bool("DJANGO_SECURE_FRAME_DENY", default=True)
+SECURE_CONTENT_TYPE_NOSNIFF = env.bool(
+    "DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True)
+SECURE_BROWSER_XSS_FILTER = True
+SESSION_COOKIE_SECURE = False
+SESSION_COOKIE_HTTPONLY = True
+SECURE_SSL_REDIRECT = env.bool("DJANGO_SECURE_SSL_REDIRECT", default=True)
+
+# SITE CONFIGURATION
+# ------------------------------------------------------------------------------
+# Hosts/domain names that are valid for this site
+# See https://docs.djangoproject.com/en/1.6/ref/settings/#allowed-hosts
+ALLOWED_HOSTS = env.list('DJANGO_ALLOWED_HOSTS', default=['ccdb.info'])
+# END SITE CONFIGURATION
+
+INSTALLED_APPS += ("gunicorn", )
+
+# STORAGE CONFIGURATION
+# ------------------------------------------------------------------------------
+# Uploaded Media Files
+# ------------------------
+# See: http://django-storages.readthedocs.org/en/latest/index.html
+INSTALLED_APPS += (
+    'storages',
+)
+DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
+
+AWS_ACCESS_KEY_ID = env('DJANGO_AWS_ACCESS_KEY_ID')
+AWS_SECRET_ACCESS_KEY = env('DJANGO_AWS_SECRET_ACCESS_KEY')
+AWS_STORAGE_BUCKET_NAME = env('DJANGO_AWS_STORAGE_BUCKET_NAME')
+AWS_AUTO_CREATE_BUCKET = True
+AWS_QUERYSTRING_AUTH = False
+AWS_S3_CALLING_FORMAT = OrdinaryCallingFormat()
+
+# AWS cache settings, don't change unless you know what you're doing:
+AWS_EXPIRY = 60 * 60 * 24 * 7
+
+# TODO See: https://github.com/jschneier/django-storages/issues/47
+# Revert the following and use str after the above-mentioned bug is fixed in
+# either django-storage-redux or boto
+AWS_HEADERS = {
+    'Cache-Control': six.b('max-age=%d, s-maxage=%d, must-revalidate' % (
+        AWS_EXPIRY, AWS_EXPIRY))
+}
+
+# URL that handles the media served from MEDIA_ROOT, used for managing
+# stored files.
+MEDIA_URL = 'https://s3.amazonaws.com/%s/' % AWS_STORAGE_BUCKET_NAME
+
+# Static Assets
+# ------------------------
+STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
+
+
+# EMAIL
+# ------------------------------------------------------------------------------
+DEFAULT_FROM_EMAIL = env('DJANGO_DEFAULT_FROM_EMAIL',
+                         default='CCDB Admin <noreply@ccdb.info>')
+EMAIL_BACKEND = 'django_mailgun.MailgunBackend'
+MAILGUN_ACCESS_KEY = env('DJANGO_MAILGUN_API_KEY')
+MAILGUN_SERVER_NAME = env('DJANGO_MAILGUN_SERVER_NAME')
+EMAIL_SUBJECT_PREFIX = env("DJANGO_EMAIL_SUBJECT_PREFIX", default='[ccdb] ')
+SERVER_EMAIL = env('DJANGO_SERVER_EMAIL', default=DEFAULT_FROM_EMAIL)
+
+
+# TEMPLATE CONFIGURATION
+# ------------------------------------------------------------------------------
+# See:
+# https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader
+TEMPLATES[0]['OPTIONS']['loaders'] = [
+    ('django.template.loaders.cached.Loader', [
+        'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', ]),
+]
+
+# DATABASE CONFIGURATION
+# ------------------------------------------------------------------------------
+# Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ
+DATABASES['default'] = env.db("DATABASE_URL")
+
+
+# LOGGING CONFIGURATION
+# ------------------------------------------------------------------------------
+# 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 http://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
+        }
+    }
+}
+
+# Custom Admin URL, use {% url 'admin:index' %}
+ADMIN_URL = env('DJANGO_ADMIN_URL')
+
+# Your production stuff: Below this line define 3rd party library settings
diff --git a/config/urls.py b/config/urls.py
new file mode 100644
index 0000000..c3b6a53
--- /dev/null
+++ b/config/urls.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.conf.urls import include, url
+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
+
+urlpatterns = [
+    url(r'^$', TemplateView.as_view(template_name='pages/home.html'), name="home"),
+    url(r'^about/$', TemplateView.as_view(template_name='pages/about.html'), name="about"),
+
+    # Django Admin, use {% url 'admin:index' %}
+    url(settings.ADMIN_URL, include(admin.site.urls)),
+
+    # User management
+    url(r'^users/', include("ccdb.users.urls", namespace="users")),
+    url(r'^accounts/', include('allauth.urls')),
+
+] + 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 += [
+        url(r'^400/$', default_views.bad_request),
+        url(r'^403/$', default_views.permission_denied),
+        url(r'^404/$', default_views.page_not_found),
+        url(r'^500/$', default_views.server_error),
+    ]
diff --git a/config/wsgi.py b/config/wsgi.py
new file mode 100644
index 0000000..2b2c014
--- /dev/null
+++ b/config/wsgi.py
@@ -0,0 +1,41 @@
+"""
+WSGI config for CCDB.
+
+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
+
+
+from django.core.wsgi import get_wsgi_application
+from whitenoise.django import DjangoWhiteNoise
+
+
+# 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()
+
+# Use Whitenoise to serve static files
+# See: https://whitenoise.readthedocs.org/
+application = DjangoWhiteNoise(application)
+
+
+# Apply WSGI middleware here.
+# from helloworld.wsgi import HelloWorldApplication
+# application = HelloWorldApplication(application)
diff --git a/manage.py b/manage.py
new file mode 100755
index 0000000..7b367ff
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
+
+    from django.core.management import execute_from_command_line
+
+    execute_from_command_line(sys.argv)
diff --git a/requirements/base.txt b/requirements/base.txt
new file mode 100644
index 0000000..7a14bf5
--- /dev/null
+++ b/requirements/base.txt
@@ -0,0 +1,32 @@
+django==1.8.6
+
+# Configuration
+django-environ==0.4.0
+django-secure==1.0.1
+whitenoise==2.0.4
+
+# Forms
+django-braces==1.8.1
+django-crispy-forms==1.5.2
+
+# Views
+django-extra-views==0.7.1
+
+# DB
+psycopg2==2.6.1
+
+# User Registration
+django-allauth==0.24.1
+
+# Unicode slugification
+unicode-slugify==0.1.3
+django-autoslug==1.9.3
+
+# Time zones support
+pytz==2015.7
+
+# Bootstrap
+django-bootstrap3==6.2.2
+
+# Data grids
+django-tables2==1.0.4
diff --git a/requirements/local.txt b/requirements/local.txt
new file mode 100644
index 0000000..7dc8189
--- /dev/null
+++ b/requirements/local.txt
@@ -0,0 +1,4 @@
+-r base.txt
+
+Werkzeug==0.10.4
+django-debug-toolbar==1.4
diff --git a/requirements/production.txt b/requirements/production.txt
new file mode 100644
index 0000000..be4cadf
--- /dev/null
+++ b/requirements/production.txt
@@ -0,0 +1,12 @@
+-r base.txt
+
+# WSGI Handler
+gevent==1.0.2
+gunicorn==19.3.0
+
+# Static and Media Storage
+boto==2.38.0
+django-storages-redux==1.3
+
+# Mailgun Support
+django-mailgun==0.8.0