diff --git a/opentech/apply/migrations/__init__.py b/opentech/apply/categories/__init__.py
similarity index 100%
rename from opentech/apply/migrations/__init__.py
rename to opentech/apply/categories/__init__.py
diff --git a/opentech/apply/categories/admin.py b/opentech/apply/categories/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..805d8aeae3a290387b25ebf04f13cba0121c7b9d
--- /dev/null
+++ b/opentech/apply/categories/admin.py
@@ -0,0 +1,9 @@
+from wagtail.contrib.modeladmin.options import ModelAdmin
+
+from .models import Category
+
+
+class CategoryAdmin(ModelAdmin):
+    menu_label = 'Category Questions'
+    menu_icon = 'list-ul'
+    model = Category
diff --git a/opentech/apply/categories/apps.py b/opentech/apply/categories/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ab5f86087f87fa5c0115ee5c5a4c1a6efccffea
--- /dev/null
+++ b/opentech/apply/categories/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class CategoriesConfig(AppConfig):
+    name = 'categories'
diff --git a/opentech/apply/blocks.py b/opentech/apply/categories/blocks.py
similarity index 87%
rename from opentech/apply/blocks.py
rename to opentech/apply/categories/blocks.py
index 1cdc8efdfeb986a2284dd536def71c87c59da024..8aa502e3afbf0593317ea7049e5e8198051d0921 100644
--- a/opentech/apply/blocks.py
+++ b/opentech/apply/categories/blocks.py
@@ -5,10 +5,10 @@ from django.utils.translation import ugettext_lazy as _
 from wagtail.wagtailcore.blocks import BooleanBlock, CharBlock, ChooserBlock, TextBlock
 from wagtail.wagtailcore.utils import resolve_model_string
 
-from opentech.stream_forms.blocks import FormFieldBlock, FormFieldsBlock
+from opentech.apply.stream_forms.blocks import FormFieldBlock
 
 
-class CategoryChooserBlock(ChooserBlock):
+class ModelChooserBlock(ChooserBlock):
     widget = forms.Select
 
     def __init__(self, target_model, **kwargs):
@@ -32,7 +32,7 @@ class CategoryQuestionBlock(FormFieldBlock):
         required=False,
         label=_('Leave blank to use the default Category help text'),
     )
-    category = CategoryChooserBlock('apply.Category')
+    category = ModelChooserBlock('categories.Category')
     multi = BooleanBlock(label='Multi select', required=False)
 
     def get_field_class(self, struct_value):
@@ -61,7 +61,3 @@ class CategoryQuestionBlock(FormFieldBlock):
             return forms.CheckboxSelectMultiple
         else:
             return forms.RadioSelect
-
-
-class CustomFormFieldsBlock(FormFieldsBlock):
-    category = CategoryQuestionBlock(group=_('Custom'))
diff --git a/opentech/apply/categories/migrations/0001_initial.py b/opentech/apply/categories/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa8ce2994a2d30959bc9dd9c466191f31832f497
--- /dev/null
+++ b/opentech/apply/categories/migrations/0001_initial.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.8 on 2018-01-09 17:52
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+import modelcluster.fields
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Category',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=255)),
+                ('help_text', models.CharField(blank=True, max_length=255)),
+            ],
+            options={
+                'verbose_name_plural': 'Categories',
+            },
+        ),
+        migrations.CreateModel(
+            name='Option',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
+                ('value', models.CharField(max_length=255)),
+                ('category', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='options', to='categories.Category')),
+            ],
+            options={
+                'ordering': ['sort_order'],
+                'abstract': False,
+            },
+        ),
+    ]
diff --git a/opentech/apply/tests/__init__.py b/opentech/apply/categories/migrations/__init__.py
similarity index 100%
rename from opentech/apply/tests/__init__.py
rename to opentech/apply/categories/migrations/__init__.py
diff --git a/opentech/apply/categories/models.py b/opentech/apply/categories/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..525cb37f7313e92478acc32fcb8164f84f6ad3c6
--- /dev/null
+++ b/opentech/apply/categories/models.py
@@ -0,0 +1,38 @@
+from django.db import models
+from modelcluster.fields import ParentalKey
+from modelcluster.models import ClusterableModel
+from wagtail.wagtailadmin.edit_handlers import (
+    FieldPanel,
+    InlinePanel,
+)
+from wagtail.wagtailcore.models import Orderable
+
+
+class Option(Orderable):
+    value = models.CharField(max_length=255)
+    category = ParentalKey('Category', related_name='options')
+
+
+class Category(ClusterableModel):
+    """Used to manage the global select questions used in most of the application form
+    Also used in the front end by editors when writing about projects.
+
+    When used in a form: name -> field label and help_text -> help_text
+    """
+    name = models.CharField(max_length=255)
+    help_text = models.CharField(max_length=255, blank=True)
+
+    @property
+    def field_label(self):
+        return self.name
+
+    panels = [
+        FieldPanel('name'),
+        InlinePanel('options', label='Options'),
+    ]
+
+    def __str__(self):
+        return self.name
+
+    class Meta:
+        verbose_name_plural = 'Categories'
diff --git a/opentech/stream_forms/tests.py b/opentech/apply/categories/tests.py
similarity index 100%
rename from opentech/stream_forms/tests.py
rename to opentech/apply/categories/tests.py
diff --git a/opentech/stream_forms/views.py b/opentech/apply/categories/views.py
similarity index 100%
rename from opentech/stream_forms/views.py
rename to opentech/apply/categories/views.py
diff --git a/opentech/forms/__init__.py b/opentech/apply/funds/__init__.py
similarity index 100%
rename from opentech/forms/__init__.py
rename to opentech/apply/funds/__init__.py
diff --git a/opentech/apply/admin.py b/opentech/apply/funds/admin.py
similarity index 70%
rename from opentech/apply/admin.py
rename to opentech/apply/funds/admin.py
index 702a83c88ff8d1b8928e1fdae4b19bfa37cdb4da..fe493151f18df7ef9b75179009eb93744298add3 100644
--- a/opentech/apply/admin.py
+++ b/opentech/apply/funds/admin.py
@@ -1,6 +1,7 @@
 from wagtail.contrib.modeladmin.options import ModelAdmin, ModelAdminGroup
 
-from .models import ApplicationForm, Category, FundType
+from .models import ApplicationForm, FundType
+from opentech.apply.categories.admin import CategoryAdmin
 
 
 class FundAdmin(ModelAdmin):
@@ -8,12 +9,6 @@ class FundAdmin(ModelAdmin):
     menu_icon = 'doc-empty'
 
 
-class CategoryAdmin(ModelAdmin):
-    menu_label = 'Category Questions'
-    menu_icon = 'list-ul'
-    model = Category
-
-
 class ApplicationFormAdmin(ModelAdmin):
     model = ApplicationForm
     menu_icon = 'form'
diff --git a/opentech/apply/apps.py b/opentech/apply/funds/apps.py
similarity index 100%
rename from opentech/apply/apps.py
rename to opentech/apply/funds/apps.py
diff --git a/opentech/apply/funds/blocks.py b/opentech/apply/funds/blocks.py
new file mode 100644
index 0000000000000000000000000000000000000000..06513827f13da391874045d3b3f3e0b8f6dc7815
--- /dev/null
+++ b/opentech/apply/funds/blocks.py
@@ -0,0 +1,9 @@
+from django.utils.translation import ugettext_lazy as _
+
+from opentech.apply.stream_forms.blocks import FormFieldsBlock
+
+from opentech.apply.categories.blocks import CategoryQuestionBlock
+
+
+class CustomFormFieldsBlock(FormFieldsBlock):
+    category = CategoryQuestionBlock(group=_('Custom'))
diff --git a/opentech/apply/forms.py b/opentech/apply/funds/forms.py
similarity index 100%
rename from opentech/apply/forms.py
rename to opentech/apply/funds/forms.py
diff --git a/opentech/apply/funds/migrations/0001_initial.py b/opentech/apply/funds/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..b148de45cbacf495758597f423ab37507c2cd2be
--- /dev/null
+++ b/opentech/apply/funds/migrations/0001_initial.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.7 on 2017-12-22 09:28
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ('images', '0001_initial'),
+        ('wagtailcore', '0040_page_draft_title'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='FundType',
+            fields=[
+                ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=('wagtailcore.page',),
+        ),
+    ]
diff --git a/opentech/apply/migrations/0003_fundpage_workflow.py b/opentech/apply/funds/migrations/0002_fundpage_workflow.py
similarity index 90%
rename from opentech/apply/migrations/0003_fundpage_workflow.py
rename to opentech/apply/funds/migrations/0002_fundpage_workflow.py
index c4c8a96c888e3051e999ade5acdd7d8c022ec9af..40f23159dde125df3a33c90eeec9ea4caf546645 100644
--- a/opentech/apply/migrations/0003_fundpage_workflow.py
+++ b/opentech/apply/funds/migrations/0002_fundpage_workflow.py
@@ -8,7 +8,7 @@ from django.db import migrations, models
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('apply', '0002_create_apply_homepage'),
+        ('funds', '0001_initial'),
     ]
 
     operations = [
diff --git a/opentech/apply/migrations/0004_applicationform_category_fundpageform_option.py b/opentech/apply/funds/migrations/0003_applicationform_category_fundpageform_option.py
similarity index 82%
rename from opentech/apply/migrations/0004_applicationform_category_fundpageform_option.py
rename to opentech/apply/funds/migrations/0003_applicationform_category_fundpageform_option.py
index 9f321277daf3654b89181a0f69cd0e32c98fae34..951b3150db0a7138812d28f3b5708031a34cb8e1 100644
--- a/opentech/apply/migrations/0004_applicationform_category_fundpageform_option.py
+++ b/opentech/apply/funds/migrations/0003_applicationform_category_fundpageform_option.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
 from django.db import migrations, models
 import django.db.models.deletion
 import modelcluster.fields
-import opentech.apply.blocks
+import opentech.apply.funds.blocks
 import wagtail.wagtailcore.blocks
 import wagtail.wagtailcore.fields
 
@@ -13,7 +13,8 @@ import wagtail.wagtailcore.fields
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('apply', '0003_fundpage_workflow'),
+        ('funds', '0002_fundpage_workflow'),
+        ('categories', '0001_initial'),
     ]
 
     operations = [
@@ -22,40 +23,16 @@ class Migration(migrations.Migration):
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                 ('name', models.CharField(max_length=255)),
-                ('form_fields', wagtail.wagtailcore.fields.StreamField((('char', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('format', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[('email', 'Email'), ('url', 'URL')], label='Format', required=False)), ('default_value', wagtail.wagtailcore.blocks.CharBlock(label='Default value', required=False))), group='Fields')), ('text', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.wagtailcore.blocks.TextBlock(label='Default value', required=False))), group='Fields')), ('number', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.wagtailcore.blocks.CharBlock(label='Default value', required=False))), group='Fields')), ('checkbox', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('default_value', wagtail.wagtailcore.blocks.BooleanBlock(required=False))), group='Fields')), ('radios', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('choices', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.CharBlock(label='Choice')))), group='Fields')), ('dropdown', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('choices', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.CharBlock(label='Choice')))), group='Fields')), ('checkboxes', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('checkboxes', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.CharBlock(label='Checkbox')))), group='Fields')), ('date', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.wagtailcore.blocks.DateBlock(required=False))), group='Fields')), ('time', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.wagtailcore.blocks.TimeBlock(required=False))), group='Fields')), ('datetime', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.wagtailcore.blocks.DateTimeBlock(required=False))), group='Fields')), ('image', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False))), group='Fields')), ('file', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False))), group='Fields')), ('text_markup', wagtail.wagtailcore.blocks.RichTextBlock(group='Other')), ('category', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(help_text='Leave blank to use the default Category label', label='Label', required=False)), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Leave blank to use the default Category help text', required=False)), ('category', opentech.apply.blocks.CategoryChooserBlock('apply.Category')), ('multi', wagtail.wagtailcore.blocks.BooleanBlock(label='Multi select', required=False))), group='Custom')))))
+                ('form_fields', wagtail.wagtailcore.fields.StreamField((('char', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('format', wagtail.wagtailcore.blocks.ChoiceBlock(choices=[('email', 'Email'), ('url', 'URL')], label='Format', required=False)), ('default_value', wagtail.wagtailcore.blocks.CharBlock(label='Default value', required=False))), group='Fields')), ('text', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.wagtailcore.blocks.TextBlock(label='Default value', required=False))), group='Fields')), ('number', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.wagtailcore.blocks.CharBlock(label='Default value', required=False))), group='Fields')), ('checkbox', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('default_value', wagtail.wagtailcore.blocks.BooleanBlock(required=False))), group='Fields')), ('radios', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('choices', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.CharBlock(label='Choice')))), group='Fields')), ('dropdown', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('choices', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.CharBlock(label='Choice')))), group='Fields')), ('checkboxes', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('checkboxes', wagtail.wagtailcore.blocks.ListBlock(wagtail.wagtailcore.blocks.CharBlock(label='Checkbox')))), group='Fields')), ('date', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.wagtailcore.blocks.DateBlock(required=False))), group='Fields')), ('time', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.wagtailcore.blocks.TimeBlock(required=False))), group='Fields')), ('datetime', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.wagtailcore.blocks.DateTimeBlock(required=False))), group='Fields')), ('image', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False))), group='Fields')), ('file', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(label='Label')), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.wagtailcore.blocks.BooleanBlock(label='Required', required=False))), group='Fields')), ('text_markup', wagtail.wagtailcore.blocks.RichTextBlock(group='Other')), ('category', wagtail.wagtailcore.blocks.StructBlock((('field_label', wagtail.wagtailcore.blocks.CharBlock(help_text='Leave blank to use the default Category label', label='Label', required=False)), ('help_text', wagtail.wagtailcore.blocks.TextBlock(label='Leave blank to use the default Category help text', required=False)), ('category', opentech.apply.categories.blocks.ModelChooserBlock('categories.Category')), ('multi', wagtail.wagtailcore.blocks.BooleanBlock(label='Multi select', required=False))), group='Custom')))))
             ],
         ),
-        migrations.CreateModel(
-            name='Category',
-            fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('name', models.CharField(max_length=255)),
-                ('help_text', models.CharField(max_length=255, blank=True)),
-            ],
-            options={
-                'verbose_name_plural': 'Categories',
-            },
-        ),
         migrations.CreateModel(
             name='FundForm',
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                 ('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
-                ('form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='apply.ApplicationForm')),
-                ('fund', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='forms', to='apply.FundType')),
-            ],
-            options={
-                'ordering': ['sort_order'],
-                'abstract': False,
-            },
-        ),
-        migrations.CreateModel(
-            name='Option',
-            fields=[
-                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
-                ('value', models.CharField(max_length=255)),
-                ('category', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='options', to='apply.Category')),
+                ('form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='funds.ApplicationForm')),
+                ('fund', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='forms', to='funds.FundType')),
             ],
             options={
                 'ordering': ['sort_order'],
diff --git a/opentech/forms/migrations/__init__.py b/opentech/apply/funds/migrations/__init__.py
similarity index 100%
rename from opentech/forms/migrations/__init__.py
rename to opentech/apply/funds/migrations/__init__.py
diff --git a/opentech/apply/funds/models.py b/opentech/apply/funds/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..6752f5165788346836a0e80d4d03a8d67ded24d7
--- /dev/null
+++ b/opentech/apply/funds/models.py
@@ -0,0 +1,69 @@
+from django.db import models
+from modelcluster.fields import ParentalKey
+from wagtail.wagtailadmin.edit_handlers import (
+    FieldPanel,
+    InlinePanel,
+    StreamFieldPanel,
+)
+from wagtail.wagtailcore.fields import StreamField
+from wagtail.wagtailcore.models import Orderable
+
+from opentech.apply.stream_forms.models import AbstractStreamForm
+
+from .blocks import CustomFormFieldsBlock
+from .forms import WorkflowFormAdminForm
+from .workflow import SingleStage, DoubleStage
+
+
+WORKFLOW_CLASS = {
+    SingleStage.name: SingleStage,
+    DoubleStage.name: DoubleStage,
+}
+
+
+class FundType(AbstractStreamForm):
+    parent_page_types = ['apply_home.ApplyHomePage']
+    subpage_types = []  # type: ignore
+
+    base_form_class = WorkflowFormAdminForm
+    WORKFLOWS = {
+        'single': SingleStage.name,
+        'double': DoubleStage.name,
+    }
+
+    workflow = models.CharField(choices=WORKFLOWS.items(), max_length=100, default='single')
+
+    def get_defined_fields(self):
+        # Only return the first form, will need updating for when working with 2 stage WF
+        return self.forms.all()[0].fields
+
+    @property
+    def workflow_class(self):
+        return WORKFLOW_CLASS[self.get_workflow_display()]
+
+    content_panels = AbstractStreamForm.content_panels + [
+        FieldPanel('workflow'),
+        InlinePanel('forms', label="Forms"),
+    ]
+
+
+class FundForm(Orderable):
+    form = models.ForeignKey('ApplicationForm')
+    fund = ParentalKey('FundType', related_name='forms')
+
+    @property
+    def fields(self):
+        return self.form.form_fields
+
+
+class ApplicationForm(models.Model):
+    name = models.CharField(max_length=255)
+    form_fields = StreamField(CustomFormFieldsBlock())
+
+    panels = [
+        FieldPanel('name'),
+        StreamFieldPanel('form_fields'),
+    ]
+
+    def __str__(self):
+        return self.name
diff --git a/opentech/apply/templates/apply/demo_workflow.html b/opentech/apply/funds/templates/funds/demo_workflow.html
similarity index 100%
rename from opentech/apply/templates/apply/demo_workflow.html
rename to opentech/apply/funds/templates/funds/demo_workflow.html
diff --git a/opentech/apply/templates/apply/fund_page.html b/opentech/apply/funds/templates/funds/fund_page.html
similarity index 100%
rename from opentech/apply/templates/apply/fund_page.html
rename to opentech/apply/funds/templates/funds/fund_page.html
diff --git a/opentech/apply/templates/apply/fund_page_landing.html b/opentech/apply/funds/templates/funds/fund_page_landing.html
similarity index 100%
rename from opentech/apply/templates/apply/fund_page_landing.html
rename to opentech/apply/funds/templates/funds/fund_page_landing.html
diff --git a/opentech/home/__init__.py b/opentech/apply/funds/tests/__init__.py
similarity index 100%
rename from opentech/home/__init__.py
rename to opentech/apply/funds/tests/__init__.py
diff --git a/opentech/apply/tests/factories.py b/opentech/apply/funds/tests/factories.py
similarity index 96%
rename from opentech/apply/tests/factories.py
rename to opentech/apply/funds/tests/factories.py
index 668a5c9e4c53f3de6d5c8ce53f34a0f710b87444..59ce824cd9c725ae836c50b3fc64927ead04a381 100644
--- a/opentech/apply/tests/factories.py
+++ b/opentech/apply/funds/tests/factories.py
@@ -2,8 +2,8 @@ from django.forms import Form
 import factory
 import wagtail_factories
 
-from opentech.apply.models import ApplicationForm, FundType, FundForm
-from opentech.apply.workflow import Action, Phase, Stage, Workflow
+from opentech.apply.funds.models import ApplicationForm, FundType, FundForm
+from opentech.apply.funds.workflow import Action, Phase, Stage, Workflow
 
 
 class ListSubFactory(factory.SubFactory):
diff --git a/opentech/apply/tests/test_admin_form.py b/opentech/apply/funds/tests/test_admin_form.py
similarity index 97%
rename from opentech/apply/tests/test_admin_form.py
rename to opentech/apply/funds/tests/test_admin_form.py
index 99551552335239744d55181489142bd9d740e812..0e2b0d7b02acee490237eaf5471a041eb56680f2 100644
--- a/opentech/apply/tests/test_admin_form.py
+++ b/opentech/apply/funds/tests/test_admin_form.py
@@ -2,7 +2,7 @@ from django.test import TestCase
 
 import factory
 
-from opentech.apply.models import FundType
+from opentech.apply.funds.models import FundType
 
 from .factories import ApplicationFormFactory, FundTypeFactory
 
diff --git a/opentech/apply/tests/test_models.py b/opentech/apply/funds/tests/test_models.py
similarity index 85%
rename from opentech/apply/tests/test_models.py
rename to opentech/apply/funds/tests/test_models.py
index 6c20a15e9bf7ec97b35b3f7619f02acfa1cf9d88..a1ba5de9ec4cb22c95db5da41d80ac8a89a8306a 100644
--- a/opentech/apply/tests/test_models.py
+++ b/opentech/apply/funds/tests/test_models.py
@@ -1,6 +1,6 @@
 from django.test import TestCase
 
-from opentech.apply.workflow import SingleStage
+from opentech.apply.funds.workflow import SingleStage
 
 from .factories import FundTypeFactory
 
diff --git a/opentech/apply/tests/test_workflow.py b/opentech/apply/funds/tests/test_workflow.py
similarity index 99%
rename from opentech/apply/tests/test_workflow.py
rename to opentech/apply/funds/tests/test_workflow.py
index 4b6cbce3c5ccbe52df7acfdda9c6eb16553358bc..ad1898c37ed551200ad44aa9a6449716b6df4cd0 100644
--- a/opentech/apply/tests/test_workflow.py
+++ b/opentech/apply/funds/tests/test_workflow.py
@@ -1,7 +1,7 @@
 from django.test import SimpleTestCase
 from django.forms import Form
 
-from opentech.apply.workflow import (
+from opentech.apply.funds.workflow import (
     Action,
     ChangePhaseAction,
     NextPhaseAction,
diff --git a/opentech/apply/funds/urls.py b/opentech/apply/funds/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..9d1bd77962f3ed7588235332bf0f14ffedc8e163
--- /dev/null
+++ b/opentech/apply/funds/urls.py
@@ -0,0 +1,7 @@
+from django.conf.urls import url
+
+from .views import demo_workflow
+
+urlpatterns = [
+    url(r'^demo/(?P<wf_id>[1-2])/$', demo_workflow, name="workflow_demo")
+]
diff --git a/opentech/apply/views.py b/opentech/apply/funds/views.py
similarity index 96%
rename from opentech/apply/views.py
rename to opentech/apply/funds/views.py
index 49fa8d1b708e88cf8359ec41e664e59fa5e6fd1b..bb3b10454f1c82a47bebcdcc1b0c48ab2f339241 100644
--- a/opentech/apply/views.py
+++ b/opentech/apply/funds/views.py
@@ -59,4 +59,4 @@ def demo_workflow(request, wf_id):
         'data': submission,
         'form': form,
     }
-    return TemplateResponse(request, 'apply/demo_workflow.html', context)
+    return TemplateResponse(request, 'funds/demo_workflow.html', context)
diff --git a/opentech/apply/wagtail_hooks.py b/opentech/apply/funds/wagtail_hooks.py
similarity index 100%
rename from opentech/apply/wagtail_hooks.py
rename to opentech/apply/funds/wagtail_hooks.py
diff --git a/opentech/apply/workflow.py b/opentech/apply/funds/workflow.py
similarity index 100%
rename from opentech/apply/workflow.py
rename to opentech/apply/funds/workflow.py
diff --git a/opentech/apply/home/__init__.py b/opentech/apply/home/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..50e120a493037e9b7abcef24dcd9cf6e555eb5e9
--- /dev/null
+++ b/opentech/apply/home/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'opentech.apply.home.apps.HomeConfig'
diff --git a/opentech/stream_forms/admin.py b/opentech/apply/home/admin.py
similarity index 100%
rename from opentech/stream_forms/admin.py
rename to opentech/apply/home/admin.py
diff --git a/opentech/apply/home/apps.py b/opentech/apply/home/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..a2bf8ec18475de73106bdbb6092b598547093bf1
--- /dev/null
+++ b/opentech/apply/home/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class HomeConfig(AppConfig):
+    name = 'opentech.apply.home'
+    label = 'apply_home'
diff --git a/opentech/apply/home/migrations/0001_initial.py b/opentech/apply/home/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..01f1ecb8ad3e095be99f2a27232f93a6e18863d4
--- /dev/null
+++ b/opentech/apply/home/migrations/0001_initial.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.8 on 2018-01-09 18:58
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ('wagtailcore', '0040_page_draft_title'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='ApplyHomePage',
+            fields=[
+                ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
+                ('strapline', models.CharField(blank=True, max_length=255)),
+            ],
+            options={
+                'abstract': False,
+            },
+            bases=('wagtailcore.page',),
+        ),
+    ]
diff --git a/opentech/apply/migrations/0002_create_apply_homepage.py b/opentech/apply/home/migrations/0002_add_apply_homepage.py
similarity index 84%
rename from opentech/apply/migrations/0002_create_apply_homepage.py
rename to opentech/apply/home/migrations/0002_add_apply_homepage.py
index 0031de11dd7d6b15681e814c0dd2f366cb231357..2055cee44418460c21c57473fa25cd37ac8aaf41 100644
--- a/opentech/apply/migrations/0002_create_apply_homepage.py
+++ b/opentech/apply/home/migrations/0002_add_apply_homepage.py
@@ -9,11 +9,11 @@ def create_homepage(apps, schema_editor):
     ContentType = apps.get_model('contenttypes.ContentType')
     Page = apps.get_model('wagtailcore.Page')
     Site = apps.get_model('wagtailcore.Site')
-    ApplyHomePage = apps.get_model('apply.ApplyHomePage')
+    ApplyHomePage = apps.get_model('apply_home.ApplyHomePage')
 
     # Create content type for homepage model
     homepage_content_type, created = ContentType.objects.get_or_create(
-        model='applyhomepage', app_label='apply')
+        model='applyhomepage', app_label='apply_home')
 
     # Create a new homepage
     applyhomepage = ApplyHomePage.objects.create(
@@ -35,8 +35,8 @@ def create_homepage(apps, schema_editor):
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('apply', '0001_initial'),
-        ('home', '0001_initial'),
+        ('funds', '0001_initial'),
+        ('apply_home', '0001_initial'),
     ]
 
     operations = [
diff --git a/opentech/home/migrations/__init__.py b/opentech/apply/home/migrations/__init__.py
similarity index 100%
rename from opentech/home/migrations/__init__.py
rename to opentech/apply/home/migrations/__init__.py
diff --git a/opentech/apply/home/models.py b/opentech/apply/home/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..31e556ede43a1726b14f838ef1c6e3fa91ce3d08
--- /dev/null
+++ b/opentech/apply/home/models.py
@@ -0,0 +1,21 @@
+from wagtail.wagtailadmin.edit_handlers import FieldPanel
+from wagtail.wagtailcore.models import Page
+from wagtail.wagtailsearch import index
+
+from django.db import models
+
+
+class ApplyHomePage(Page):
+    # Only allow creating HomePages at the root level
+    parent_page_types = ['wagtailcore.Page']
+    subpage_types = ['funds.FundType']
+
+    strapline = models.CharField(blank=True, max_length=255)
+
+    search_fields = Page.search_fields + [
+        index.SearchField('strapline'),
+    ]
+
+    content_panels = Page.content_panels + [
+        FieldPanel('strapline'),
+    ]
diff --git a/opentech/apply/home/tests.py b/opentech/apply/home/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..a79ca8be565f44aacce95bad20c1ee34d175ed20
--- /dev/null
+++ b/opentech/apply/home/tests.py
@@ -0,0 +1,3 @@
+# from django.test import TestCase
+
+# Create your tests here.
diff --git a/opentech/apply/home/views.py b/opentech/apply/home/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd0e0449559b2e00e226cc9f96df7caed44172aa
--- /dev/null
+++ b/opentech/apply/home/views.py
@@ -0,0 +1,3 @@
+# from django.shortcuts import render
+
+# Create your views here.
diff --git a/opentech/apply/migrations/0001_initial.py b/opentech/apply/migrations/0001_initial.py
deleted file mode 100644
index de0c87693032cddda697855ab46c33faf5a932fc..0000000000000000000000000000000000000000
--- a/opentech/apply/migrations/0001_initial.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.11.7 on 2017-12-22 09:28
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    initial = True
-
-    dependencies = [
-        ('images', '0001_initial'),
-        ('wagtailcore', '0040_page_draft_title'),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='ApplyHomePage',
-            fields=[
-                ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
-                ('social_text', models.CharField(blank=True, max_length=255)),
-                ('listing_title', models.CharField(blank=True, help_text='Override the page title used when this page appears in listings', max_length=255)),
-                ('listing_summary', models.CharField(blank=True, help_text="The text summary used when this page appears in listings. It's also used as the description for search engines if the 'Search description' field above is not defined.", max_length=255)),
-                ('strapline', models.CharField(blank=True, max_length=255)),
-                ('listing_image', models.ForeignKey(blank=True, help_text='Choose the image you wish to be displayed when this page appears in listings', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.CustomImage')),
-                ('social_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.CustomImage')),
-            ],
-            options={
-                'abstract': False,
-            },
-            bases=('wagtailcore.page', models.Model),
-        ),
-        migrations.CreateModel(
-            name='FundType',
-            fields=[
-                ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')),
-            ],
-            options={
-                'abstract': False,
-            },
-            bases=('wagtailcore.page',),
-        ),
-    ]
diff --git a/opentech/apply/models.py b/opentech/apply/models.py
deleted file mode 100644
index 1c7355922a3ae9f6faa5c8a63243b13828f5da9d..0000000000000000000000000000000000000000
--- a/opentech/apply/models.py
+++ /dev/null
@@ -1,124 +0,0 @@
-from django.db import models
-from modelcluster.fields import ParentalKey
-from modelcluster.models import ClusterableModel
-from wagtail.wagtailadmin.edit_handlers import (
-    FieldPanel,
-    InlinePanel,
-    StreamFieldPanel,
-)
-from wagtail.wagtailcore.fields import StreamField
-from wagtail.wagtailcore.models import Orderable, Page
-from wagtail.wagtailsearch import index
-
-from opentech.stream_forms.models import AbstractStreamForm
-from opentech.utils.models import SocialFields, ListingFields
-
-from .blocks import CustomFormFieldsBlock
-from .forms import WorkflowFormAdminForm
-from .workflow import SingleStage, DoubleStage
-
-
-WORKFLOW_CLASS = {
-    SingleStage.name: SingleStage,
-    DoubleStage.name: DoubleStage,
-}
-
-
-class ApplyHomePage(Page, SocialFields, ListingFields):  # type: ignore
-    # Only allow creating HomePages at the root level
-    parent_page_types = ['wagtailcore.Page']
-    subpage_types = ['FundType']
-
-    strapline = models.CharField(blank=True, max_length=255)
-
-    search_fields = Page.search_fields + [
-        index.SearchField('strapline'),
-    ]
-
-    content_panels = Page.content_panels + [
-        FieldPanel('strapline'),
-    ]
-
-    promote_panels = (
-        Page.promote_panels +
-        SocialFields.promote_panels +
-        ListingFields.promote_panels
-    )
-
-
-class FundType(AbstractStreamForm):
-    parent_page_types = [ApplyHomePage]
-    subpage_types = []  # type: ignore
-
-    base_form_class = WorkflowFormAdminForm
-    WORKFLOWS = {
-        'single': SingleStage.name,
-        'double': DoubleStage.name,
-    }
-
-    workflow = models.CharField(choices=WORKFLOWS.items(), max_length=100, default='single')
-
-    def get_defined_fields(self):
-        # Only return the first form, will need updating for when working with 2 stage WF
-        return self.forms.all()[0].fields
-
-    @property
-    def workflow_class(self):
-        return WORKFLOW_CLASS[self.get_workflow_display()]
-
-    content_panels = AbstractStreamForm.content_panels + [
-        FieldPanel('workflow'),
-        InlinePanel('forms', label="Forms"),
-    ]
-
-
-class FundForm(Orderable):
-    form = models.ForeignKey('ApplicationForm')
-    fund = ParentalKey('FundType', related_name='forms')
-
-    @property
-    def fields(self):
-        return self.form.form_fields
-
-
-class ApplicationForm(models.Model):
-    name = models.CharField(max_length=255)
-    form_fields = StreamField(CustomFormFieldsBlock())
-
-    panels = [
-        FieldPanel('name'),
-        StreamFieldPanel('form_fields'),
-    ]
-
-    def __str__(self):
-        return self.name
-
-
-class Option(Orderable):
-    value = models.CharField(max_length=255)
-    category = ParentalKey('Category', related_name='options')
-
-
-class Category(ClusterableModel):
-    """Used to manage the global select questions used in most of the application form
-    Also used in the front end by editors when writing about projects.
-
-    When used in a form: name -> field label and help_text -> help_text
-    """
-    name = models.CharField(max_length=255)
-    help_text = models.CharField(max_length=255, blank=True)
-
-    @property
-    def field_label(self):
-        return self.name
-
-    panels = [
-        FieldPanel('name'),
-        InlinePanel('options', label='Options'),
-    ]
-
-    def __str__(self):
-        return self.name
-
-    class Meta:
-        verbose_name_plural = 'Categories'
diff --git a/opentech/navigation/__init__.py b/opentech/apply/stream_forms/__init__.py
similarity index 100%
rename from opentech/navigation/__init__.py
rename to opentech/apply/stream_forms/__init__.py
diff --git a/opentech/apply/stream_forms/admin.py b/opentech/apply/stream_forms/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..4185d360e9a725a190ddfd9b8cce8aeb0df64cc3
--- /dev/null
+++ b/opentech/apply/stream_forms/admin.py
@@ -0,0 +1,3 @@
+# from django.contrib import admin
+
+# Register your models here.
diff --git a/opentech/stream_forms/apps.py b/opentech/apply/stream_forms/apps.py
similarity index 100%
rename from opentech/stream_forms/apps.py
rename to opentech/apply/stream_forms/apps.py
diff --git a/opentech/stream_forms/blocks.py b/opentech/apply/stream_forms/blocks.py
similarity index 100%
rename from opentech/stream_forms/blocks.py
rename to opentech/apply/stream_forms/blocks.py
diff --git a/opentech/stream_forms/forms.py b/opentech/apply/stream_forms/forms.py
similarity index 100%
rename from opentech/stream_forms/forms.py
rename to opentech/apply/stream_forms/forms.py
diff --git a/opentech/navigation/migrations/__init__.py b/opentech/apply/stream_forms/migrations/__init__.py
similarity index 100%
rename from opentech/navigation/migrations/__init__.py
rename to opentech/apply/stream_forms/migrations/__init__.py
diff --git a/opentech/stream_forms/models.py b/opentech/apply/stream_forms/models.py
similarity index 100%
rename from opentech/stream_forms/models.py
rename to opentech/apply/stream_forms/models.py
diff --git a/opentech/apply/stream_forms/tests.py b/opentech/apply/stream_forms/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..a79ca8be565f44aacce95bad20c1ee34d175ed20
--- /dev/null
+++ b/opentech/apply/stream_forms/tests.py
@@ -0,0 +1,3 @@
+# from django.test import TestCase
+
+# Create your tests here.
diff --git a/opentech/apply/stream_forms/views.py b/opentech/apply/stream_forms/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..fd0e0449559b2e00e226cc9f96df7caed44172aa
--- /dev/null
+++ b/opentech/apply/stream_forms/views.py
@@ -0,0 +1,3 @@
+# from django.shortcuts import render
+
+# Create your views here.
diff --git a/opentech/apply/urls.py b/opentech/apply/urls.py
index 9d1bd77962f3ed7588235332bf0f14ffedc8e163..a7487aaf5f3d029ec18b832ce8b329a2f6c32052 100644
--- a/opentech/apply/urls.py
+++ b/opentech/apply/urls.py
@@ -1,7 +1,9 @@
-from django.conf.urls import url
+from django.conf.urls import include, url
 
-from .views import demo_workflow
+from .funds import urls as funds_urls
+from .users import urls as users_urls
 
 urlpatterns = [
-    url(r'^demo/(?P<wf_id>[1-2])/$', demo_workflow, name="workflow_demo")
+    url(r'^apply/', include(funds_urls)),
+    url(r'^user/', include(users_urls))
 ]
diff --git a/opentech/navigation/templatetags/__init__.py b/opentech/apply/users/__init__.py
similarity index 100%
rename from opentech/navigation/templatetags/__init__.py
rename to opentech/apply/users/__init__.py
diff --git a/opentech/users/groups.py b/opentech/apply/users/groups.py
similarity index 100%
rename from opentech/users/groups.py
rename to opentech/apply/users/groups.py
diff --git a/opentech/users/migrations/0001_initial.py b/opentech/apply/users/migrations/0001_initial.py
similarity index 100%
rename from opentech/users/migrations/0001_initial.py
rename to opentech/apply/users/migrations/0001_initial.py
diff --git a/opentech/users/migrations/0002_initial_data.py b/opentech/apply/users/migrations/0002_initial_data.py
similarity index 96%
rename from opentech/users/migrations/0002_initial_data.py
rename to opentech/apply/users/migrations/0002_initial_data.py
index f42a221ca9c95b6785c076787e7903f91322e5a1..20ae2395e2a2d2981eafb192f89bfdb154bd72b7 100644
--- a/opentech/users/migrations/0002_initial_data.py
+++ b/opentech/apply/users/migrations/0002_initial_data.py
@@ -6,7 +6,7 @@ from django.core.exceptions import ObjectDoesNotExist
 from django.core.management.sql import emit_post_migrate_signal
 from django.db import migrations
 
-from opentech.users.groups import GROUPS
+from opentech.apply.users.groups import GROUPS
 
 
 def add_groups(apps, schema_editor):
diff --git a/opentech/news/__init__.py b/opentech/apply/users/migrations/__init__.py
similarity index 100%
rename from opentech/news/__init__.py
rename to opentech/apply/users/migrations/__init__.py
diff --git a/opentech/users/models.py b/opentech/apply/users/models.py
similarity index 100%
rename from opentech/users/models.py
rename to opentech/apply/users/models.py
diff --git a/opentech/users/templates/users/login.html b/opentech/apply/users/templates/users/login.html
similarity index 100%
rename from opentech/users/templates/users/login.html
rename to opentech/apply/users/templates/users/login.html
diff --git a/opentech/users/urls.py b/opentech/apply/users/urls.py
similarity index 100%
rename from opentech/users/urls.py
rename to opentech/apply/users/urls.py
diff --git a/opentech/users/views.py b/opentech/apply/users/views.py
similarity index 100%
rename from opentech/users/views.py
rename to opentech/apply/users/views.py
diff --git a/opentech/images/models.py b/opentech/images/models.py
index 1da5bd25ea5789138f056843d7c67aa1b36b3960..4740e7d04d5420625a5f2ac4663182e94db914b8 100644
--- a/opentech/images/models.py
+++ b/opentech/images/models.py
@@ -1,6 +1,9 @@
 from django.db import models
-from wagtail.wagtailimages.models import (AbstractImage, AbstractRendition,
-                                          Image)
+from wagtail.wagtailimages.models import (
+    AbstractImage,
+    AbstractRendition,
+    Image,
+)
 
 
 # We define our own custom image class to replace wagtailimages.Image,
diff --git a/opentech/news/migrations/__init__.py b/opentech/public/__init__.py
similarity index 100%
rename from opentech/news/migrations/__init__.py
rename to opentech/public/__init__.py
diff --git a/opentech/esi/__init__.py b/opentech/public/esi/__init__.py
similarity index 100%
rename from opentech/esi/__init__.py
rename to opentech/public/esi/__init__.py
diff --git a/opentech/esi/middleware.py b/opentech/public/esi/middleware.py
similarity index 100%
rename from opentech/esi/middleware.py
rename to opentech/public/esi/middleware.py
diff --git a/opentech/esi/models.py b/opentech/public/esi/models.py
similarity index 100%
rename from opentech/esi/models.py
rename to opentech/public/esi/models.py
diff --git a/opentech/esi/views.py b/opentech/public/esi/views.py
similarity index 83%
rename from opentech/esi/views.py
rename to opentech/public/esi/views.py
index 13ad891fbf0cca668b69331dd3b22b7dddc061fb..ae12f4d880e709dbac185b83973b5ac5b5133760 100644
--- a/opentech/esi/views.py
+++ b/opentech/public/esi/views.py
@@ -1,6 +1,6 @@
 from django.shortcuts import render_to_response
 
-from opentech.esi import ESI_REGISTRY
+from opentech.public.esi import ESI_REGISTRY
 
 
 def esi(request, name):
diff --git a/opentech/people/__init__.py b/opentech/public/forms/__init__.py
similarity index 100%
rename from opentech/people/__init__.py
rename to opentech/public/forms/__init__.py
diff --git a/opentech/forms/migrations/0001_initial.py b/opentech/public/forms/migrations/0001_initial.py
similarity index 100%
rename from opentech/forms/migrations/0001_initial.py
rename to opentech/public/forms/migrations/0001_initial.py
diff --git a/opentech/forms/migrations/0002_formpage_header_image.py b/opentech/public/forms/migrations/0002_formpage_header_image.py
similarity index 100%
rename from opentech/forms/migrations/0002_formpage_header_image.py
rename to opentech/public/forms/migrations/0002_formpage_header_image.py
diff --git a/opentech/people/migrations/__init__.py b/opentech/public/forms/migrations/__init__.py
similarity index 100%
rename from opentech/people/migrations/__init__.py
rename to opentech/public/forms/migrations/__init__.py
diff --git a/opentech/forms/models.py b/opentech/public/forms/models.py
similarity index 96%
rename from opentech/forms/models.py
rename to opentech/public/forms/models.py
index 0ca50f6cd36cf1865ddc1b5bf75a9c0f734feb3d..e1db90738f92e91f4677d8fe5c1a18d888969a37 100644
--- a/opentech/forms/models.py
+++ b/opentech/public/forms/models.py
@@ -12,7 +12,7 @@ from wagtail.wagtailsearch import index
 
 from wagtailcaptcha.models import WagtailCaptchaEmailForm
 
-from opentech.utils.models import BasePage
+from opentech.public.utils.models import BasePage
 
 
 class FormField(AbstractFormField):
diff --git a/opentech/forms/templates/forms/form_page.html b/opentech/public/forms/templates/forms/form_page.html
similarity index 100%
rename from opentech/forms/templates/forms/form_page.html
rename to opentech/public/forms/templates/forms/form_page.html
diff --git a/opentech/forms/templates/forms/form_page_landing.html b/opentech/public/forms/templates/forms/form_page_landing.html
similarity index 100%
rename from opentech/forms/templates/forms/form_page_landing.html
rename to opentech/public/forms/templates/forms/form_page_landing.html
diff --git a/opentech/search/__init__.py b/opentech/public/home/__init__.py
similarity index 100%
rename from opentech/search/__init__.py
rename to opentech/public/home/__init__.py
diff --git a/opentech/home/migrations/0001_initial.py b/opentech/public/home/migrations/0001_initial.py
similarity index 100%
rename from opentech/home/migrations/0001_initial.py
rename to opentech/public/home/migrations/0001_initial.py
diff --git a/opentech/home/migrations/0002_create_homepage.py b/opentech/public/home/migrations/0002_create_homepage.py
similarity index 100%
rename from opentech/home/migrations/0002_create_homepage.py
rename to opentech/public/home/migrations/0002_create_homepage.py
diff --git a/opentech/home/migrations/0003_homepage_header_image.py b/opentech/public/home/migrations/0003_homepage_header_image.py
similarity index 100%
rename from opentech/home/migrations/0003_homepage_header_image.py
rename to opentech/public/home/migrations/0003_homepage_header_image.py
diff --git a/opentech/standardpages/__init__.py b/opentech/public/home/migrations/__init__.py
similarity index 100%
rename from opentech/standardpages/__init__.py
rename to opentech/public/home/migrations/__init__.py
diff --git a/opentech/home/models.py b/opentech/public/home/models.py
similarity index 93%
rename from opentech/home/models.py
rename to opentech/public/home/models.py
index f99f2b6e57b3b47857e600e9119b8c1f23189588..0ea271a30859ab022c9d1fc6d504fe20d1f6fabe 100644
--- a/opentech/home/models.py
+++ b/opentech/public/home/models.py
@@ -4,7 +4,7 @@ from wagtail.wagtailadmin.edit_handlers import FieldPanel
 from wagtail.wagtailsearch import index
 from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel
 
-from opentech.utils.models import BasePage
+from opentech.public.utils.models import BasePage
 
 
 class HomePage(BasePage):
diff --git a/opentech/home/templates/home/home_page.html b/opentech/public/home/templates/home/home_page.html
similarity index 100%
rename from opentech/home/templates/home/home_page.html
rename to opentech/public/home/templates/home/home_page.html
diff --git a/opentech/standardpages/migrations/__init__.py b/opentech/public/navigation/__init__.py
similarity index 100%
rename from opentech/standardpages/migrations/__init__.py
rename to opentech/public/navigation/__init__.py
diff --git a/opentech/navigation/migrations/0001_initial.py b/opentech/public/navigation/migrations/0001_initial.py
similarity index 100%
rename from opentech/navigation/migrations/0001_initial.py
rename to opentech/public/navigation/migrations/0001_initial.py
diff --git a/opentech/stream_forms/__init__.py b/opentech/public/navigation/migrations/__init__.py
similarity index 100%
rename from opentech/stream_forms/__init__.py
rename to opentech/public/navigation/migrations/__init__.py
diff --git a/opentech/navigation/models.py b/opentech/public/navigation/models.py
similarity index 97%
rename from opentech/navigation/models.py
rename to opentech/public/navigation/models.py
index c270b1478b29b4a670b1e6a07e2c667da83a485d..137d92d7d65f2aca00981be11f55a6b5441ec2bf 100644
--- a/opentech/navigation/models.py
+++ b/opentech/public/navigation/models.py
@@ -4,7 +4,7 @@ from wagtail.wagtailadmin.edit_handlers import StreamFieldPanel
 from wagtail.wagtailcore import blocks
 from wagtail.wagtailcore.fields import StreamField
 
-from opentech.esi import purge_esi
+from opentech.public.esi import purge_esi
 
 
 class LinkBlock(blocks.StructBlock):
diff --git a/opentech/navigation/templates/navigation/blocks/footer_column.html b/opentech/public/navigation/templates/navigation/blocks/footer_column.html
similarity index 100%
rename from opentech/navigation/templates/navigation/blocks/footer_column.html
rename to opentech/public/navigation/templates/navigation/blocks/footer_column.html
diff --git a/opentech/navigation/templates/navigation/blocks/menu_item.html b/opentech/public/navigation/templates/navigation/blocks/menu_item.html
similarity index 100%
rename from opentech/navigation/templates/navigation/blocks/menu_item.html
rename to opentech/public/navigation/templates/navigation/blocks/menu_item.html
diff --git a/opentech/navigation/templates/navigation/breadcrumbs.html b/opentech/public/navigation/templates/navigation/breadcrumbs.html
similarity index 100%
rename from opentech/navigation/templates/navigation/breadcrumbs.html
rename to opentech/public/navigation/templates/navigation/breadcrumbs.html
diff --git a/opentech/navigation/templates/navigation/footerlinks.html b/opentech/public/navigation/templates/navigation/footerlinks.html
similarity index 100%
rename from opentech/navigation/templates/navigation/footerlinks.html
rename to opentech/public/navigation/templates/navigation/footerlinks.html
diff --git a/opentech/navigation/templates/navigation/footernav.html b/opentech/public/navigation/templates/navigation/footernav.html
similarity index 100%
rename from opentech/navigation/templates/navigation/footernav.html
rename to opentech/public/navigation/templates/navigation/footernav.html
diff --git a/opentech/navigation/templates/navigation/includes/menu_item.html b/opentech/public/navigation/templates/navigation/includes/menu_item.html
similarity index 100%
rename from opentech/navigation/templates/navigation/includes/menu_item.html
rename to opentech/public/navigation/templates/navigation/includes/menu_item.html
diff --git a/opentech/navigation/templates/navigation/primarynav.html b/opentech/public/navigation/templates/navigation/primarynav.html
similarity index 100%
rename from opentech/navigation/templates/navigation/primarynav.html
rename to opentech/public/navigation/templates/navigation/primarynav.html
diff --git a/opentech/navigation/templates/navigation/secondarynav.html b/opentech/public/navigation/templates/navigation/secondarynav.html
similarity index 100%
rename from opentech/navigation/templates/navigation/secondarynav.html
rename to opentech/public/navigation/templates/navigation/secondarynav.html
diff --git a/opentech/navigation/templates/navigation/sidebar.html b/opentech/public/navigation/templates/navigation/sidebar.html
similarity index 100%
rename from opentech/navigation/templates/navigation/sidebar.html
rename to opentech/public/navigation/templates/navigation/sidebar.html
diff --git a/opentech/stream_forms/migrations/__init__.py b/opentech/public/navigation/templatetags/__init__.py
similarity index 100%
rename from opentech/stream_forms/migrations/__init__.py
rename to opentech/public/navigation/templatetags/__init__.py
diff --git a/opentech/navigation/templatetags/navigation_tags.py b/opentech/public/navigation/templatetags/navigation_tags.py
similarity index 92%
rename from opentech/navigation/templatetags/navigation_tags.py
rename to opentech/public/navigation/templatetags/navigation_tags.py
index 0d1eabdc3ba108436aaf2c29eabce6fc387c43e8..9682f7aa73db6bb8507c549fe7236184c42ccc23 100644
--- a/opentech/navigation/templatetags/navigation_tags.py
+++ b/opentech/public/navigation/templatetags/navigation_tags.py
@@ -1,7 +1,7 @@
 from django import template
 
-from opentech.esi import register_inclusion_tag
-from opentech.navigation.models import NavigationSettings
+from opentech.public.esi import register_inclusion_tag
+from opentech.public.navigation.models import NavigationSettings
 
 
 register = template.Library()
diff --git a/opentech/users/__init__.py b/opentech/public/news/__init__.py
similarity index 100%
rename from opentech/users/__init__.py
rename to opentech/public/news/__init__.py
diff --git a/opentech/news/migrations/0001_initial.py b/opentech/public/news/migrations/0001_initial.py
similarity index 100%
rename from opentech/news/migrations/0001_initial.py
rename to opentech/public/news/migrations/0001_initial.py
diff --git a/opentech/news/migrations/0002_add_header_image.py b/opentech/public/news/migrations/0002_add_header_image.py
similarity index 100%
rename from opentech/news/migrations/0002_add_header_image.py
rename to opentech/public/news/migrations/0002_add_header_image.py
diff --git a/opentech/news/migrations/0003_newspageauthor.py b/opentech/public/news/migrations/0003_newspageauthor.py
similarity index 100%
rename from opentech/news/migrations/0003_newspageauthor.py
rename to opentech/public/news/migrations/0003_newspageauthor.py
diff --git a/opentech/users/migrations/__init__.py b/opentech/public/news/migrations/__init__.py
similarity index 100%
rename from opentech/users/migrations/__init__.py
rename to opentech/public/news/migrations/__init__.py
diff --git a/opentech/news/models.py b/opentech/public/news/models.py
similarity index 96%
rename from opentech/news/models.py
rename to opentech/public/news/models.py
index 7210cdbcd89f7d640692d301787bcc58bd6f5b62..6915ec1efbe8c897520533fc85c909a5ef9fdcb1 100644
--- a/opentech/news/models.py
+++ b/opentech/public/news/models.py
@@ -15,8 +15,8 @@ from wagtail.wagtailadmin.edit_handlers import (
 )
 from wagtail.wagtailsearch import index
 
-from opentech.utils.models import BasePage, RelatedPage
-from opentech.utils.blocks import StoryBlock
+from opentech.public.utils.models import BasePage, RelatedPage
+from opentech.public.utils.blocks import StoryBlock
 
 
 class NewsType(models.Model):
diff --git a/opentech/news/templates/news/news_index.html b/opentech/public/news/templates/news/news_index.html
similarity index 100%
rename from opentech/news/templates/news/news_index.html
rename to opentech/public/news/templates/news/news_index.html
diff --git a/opentech/news/templates/news/news_page.html b/opentech/public/news/templates/news/news_page.html
similarity index 100%
rename from opentech/news/templates/news/news_page.html
rename to opentech/public/news/templates/news/news_page.html
diff --git a/opentech/utils/__init__.py b/opentech/public/people/__init__.py
similarity index 100%
rename from opentech/utils/__init__.py
rename to opentech/public/people/__init__.py
diff --git a/opentech/people/migrations/0001_initial.py b/opentech/public/people/migrations/0001_initial.py
similarity index 99%
rename from opentech/people/migrations/0001_initial.py
rename to opentech/public/people/migrations/0001_initial.py
index bc4e0aea611736501c084a5e8305d1024bbc0cf5..15720a79dd27cb3b2507d2e71337a1c3d74c9404 100644
--- a/opentech/people/migrations/0001_initial.py
+++ b/opentech/public/people/migrations/0001_initial.py
@@ -2,7 +2,7 @@
 # Generated by Django 1.10.7 on 2017-04-14 09:29
 from __future__ import unicode_literals
 
-import opentech.utils.models
+import opentech.public.utils.models
 from django.db import migrations, models
 import django.db.models.deletion
 import modelcluster.fields
diff --git a/opentech/people/migrations/0002_add_header_image.py b/opentech/public/people/migrations/0002_add_header_image.py
similarity index 100%
rename from opentech/people/migrations/0002_add_header_image.py
rename to opentech/public/people/migrations/0002_add_header_image.py
diff --git a/opentech/utils/migrations/__init__.py b/opentech/public/people/migrations/__init__.py
similarity index 100%
rename from opentech/utils/migrations/__init__.py
rename to opentech/public/people/migrations/__init__.py
diff --git a/opentech/people/models.py b/opentech/public/people/models.py
similarity index 97%
rename from opentech/people/models.py
rename to opentech/public/people/models.py
index af91d665a7849423b6ef4958235354ee727bfa3d..0534a032ec2055785e24883e739908b325ab2ff1 100644
--- a/opentech/people/models.py
+++ b/opentech/public/people/models.py
@@ -14,8 +14,8 @@ from wagtail.wagtailadmin.edit_handlers import (
 )
 from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
 
-from opentech.utils.blocks import StoryBlock
-from opentech.utils.models import BasePage
+from opentech.public.utils.blocks import StoryBlock
+from opentech.public.utils.models import BasePage
 
 
 class SocialMediaProfile(models.Model):
diff --git a/opentech/people/static/people/admin/js/update_person_title.js b/opentech/public/people/static/people/admin/js/update_person_title.js
similarity index 100%
rename from opentech/people/static/people/admin/js/update_person_title.js
rename to opentech/public/people/static/people/admin/js/update_person_title.js
diff --git a/opentech/people/templates/people/person_index_page.html b/opentech/public/people/templates/people/person_index_page.html
similarity index 100%
rename from opentech/people/templates/people/person_index_page.html
rename to opentech/public/people/templates/people/person_index_page.html
diff --git a/opentech/people/templates/people/person_page.html b/opentech/public/people/templates/people/person_page.html
similarity index 100%
rename from opentech/people/templates/people/person_page.html
rename to opentech/public/people/templates/people/person_page.html
diff --git a/opentech/people/wagtail_hooks.py b/opentech/public/people/wagtail_hooks.py
similarity index 100%
rename from opentech/people/wagtail_hooks.py
rename to opentech/public/people/wagtail_hooks.py
diff --git a/opentech/utils/templatetags/__init__.py b/opentech/public/search/__init__.py
similarity index 100%
rename from opentech/utils/templatetags/__init__.py
rename to opentech/public/search/__init__.py
diff --git a/opentech/search/templates/search/includes/search_result.html b/opentech/public/search/templates/search/includes/search_result.html
similarity index 100%
rename from opentech/search/templates/search/includes/search_result.html
rename to opentech/public/search/templates/search/includes/search_result.html
diff --git a/opentech/search/templates/search/search.html b/opentech/public/search/templates/search/search.html
similarity index 100%
rename from opentech/search/templates/search/search.html
rename to opentech/public/search/templates/search/search.html
diff --git a/opentech/search/views.py b/opentech/public/search/views.py
similarity index 100%
rename from opentech/search/views.py
rename to opentech/public/search/views.py
diff --git a/opentech/public/standardpages/__init__.py b/opentech/public/standardpages/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/opentech/standardpages/migrations/0001_initial.py b/opentech/public/standardpages/migrations/0001_initial.py
similarity index 100%
rename from opentech/standardpages/migrations/0001_initial.py
rename to opentech/public/standardpages/migrations/0001_initial.py
diff --git a/opentech/standardpages/migrations/0002_add_header_image.py b/opentech/public/standardpages/migrations/0002_add_header_image.py
similarity index 100%
rename from opentech/standardpages/migrations/0002_add_header_image.py
rename to opentech/public/standardpages/migrations/0002_add_header_image.py
diff --git a/opentech/public/standardpages/migrations/__init__.py b/opentech/public/standardpages/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/opentech/standardpages/models.py b/opentech/public/standardpages/models.py
similarity index 95%
rename from opentech/standardpages/models.py
rename to opentech/public/standardpages/models.py
index 754aa1fca94e2e860922b80489286b70ef86041a..5125691268a3c0982d1ffdbc36e6f541f5f73805 100644
--- a/opentech/standardpages/models.py
+++ b/opentech/public/standardpages/models.py
@@ -11,8 +11,8 @@ from wagtail.wagtailadmin.edit_handlers import (
 from wagtail.wagtailcore.fields import StreamField
 from wagtail.wagtailsearch import index
 
-from opentech.utils.blocks import StoryBlock
-from opentech.utils.models import (
+from opentech.public.utils.blocks import StoryBlock
+from opentech.public.utils.models import (
     BasePage,
     RelatedPage,
 )
diff --git a/opentech/standardpages/templates/standardpages/index_page.html b/opentech/public/standardpages/templates/standardpages/index_page.html
similarity index 100%
rename from opentech/standardpages/templates/standardpages/index_page.html
rename to opentech/public/standardpages/templates/standardpages/index_page.html
diff --git a/opentech/standardpages/templates/standardpages/information_page.html b/opentech/public/standardpages/templates/standardpages/information_page.html
similarity index 100%
rename from opentech/standardpages/templates/standardpages/information_page.html
rename to opentech/public/standardpages/templates/standardpages/information_page.html
diff --git a/opentech/public/urls.py b/opentech/public/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..9caea43477cc74e124ac58d307a36768860d062d
--- /dev/null
+++ b/opentech/public/urls.py
@@ -0,0 +1,9 @@
+from django.conf.urls import url
+
+from .esi import views as esi_views
+from .search import views as search_views
+
+urlpatterns = [
+    url(r'^esi/(.*)/$', esi_views.esi, name='esi'),
+    url(r'^search/$', search_views.search, name='search'),
+]
diff --git a/opentech/public/utils/__init__.py b/opentech/public/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/opentech/utils/blocks.py b/opentech/public/utils/blocks.py
similarity index 100%
rename from opentech/utils/blocks.py
rename to opentech/public/utils/blocks.py
diff --git a/opentech/utils/cache.py b/opentech/public/utils/cache.py
similarity index 100%
rename from opentech/utils/cache.py
rename to opentech/public/utils/cache.py
diff --git a/opentech/utils/context_processors.py b/opentech/public/utils/context_processors.py
similarity index 100%
rename from opentech/utils/context_processors.py
rename to opentech/public/utils/context_processors.py
diff --git a/opentech/utils/migrations/0001_initial.py b/opentech/public/utils/migrations/0001_initial.py
similarity index 100%
rename from opentech/utils/migrations/0001_initial.py
rename to opentech/public/utils/migrations/0001_initial.py
diff --git a/opentech/public/utils/migrations/__init__.py b/opentech/public/utils/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/opentech/utils/models.py b/opentech/public/utils/models.py
similarity index 100%
rename from opentech/utils/models.py
rename to opentech/public/utils/models.py
diff --git a/opentech/public/utils/templatetags/__init__.py b/opentech/public/utils/templatetags/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/opentech/utils/templatetags/util_tags.py b/opentech/public/utils/templatetags/util_tags.py
similarity index 91%
rename from opentech/utils/templatetags/util_tags.py
rename to opentech/public/utils/templatetags/util_tags.py
index 899e5e5fa5bcb3917099dace9f563fd951775302..bf577d312c6dd797f3b102b8f6f332eed0d97747 100644
--- a/opentech/utils/templatetags/util_tags.py
+++ b/opentech/public/utils/templatetags/util_tags.py
@@ -2,7 +2,7 @@ from django import template
 
 from wagtail.wagtailcore.utils import camelcase_to_underscore
 
-from opentech.utils.models import SocialMediaSettings
+from opentech.public.utils.models import SocialMediaSettings
 
 
 register = template.Library()
diff --git a/opentech/utils/wagtail_hooks.py b/opentech/public/utils/wagtail_hooks.py
similarity index 82%
rename from opentech/utils/wagtail_hooks.py
rename to opentech/public/utils/wagtail_hooks.py
index 9030a5ea6608e51a55f8d132d3b48d1f9cb3e770..ec99c6dc25710552d8f0cf59acc69216fcde660c 100644
--- a/opentech/utils/wagtail_hooks.py
+++ b/opentech/public/utils/wagtail_hooks.py
@@ -1,8 +1,8 @@
 from wagtail.contrib.modeladmin.options import ModelAdminGroup, ModelAdmin, modeladmin_register
 
 
-from opentech.news.models import NewsType
-from opentech.people.models import PersonType
+from opentech.public.news.models import NewsType
+from opentech.public.people.models import PersonType
 
 
 class NewsTypeModelAdmin(ModelAdmin):
diff --git a/opentech/settings/base.py b/opentech/settings/base.py
index b729602eabd7d313a5d7c63fd9c31ab2d8cb2d9e..5aaf1a75957fd821d8260707e8c2c7982ee6919b 100644
--- a/opentech/settings/base.py
+++ b/opentech/settings/base.py
@@ -12,19 +12,23 @@ BASE_DIR = os.path.dirname(PROJECT_DIR)
 # Application definition
 
 INSTALLED_APPS = [
-    'opentech.apply',
-    'opentech.esi',
-    'opentech.forms',
-    'opentech.home',
     'opentech.images',
-    'opentech.navigation',
-    'opentech.news',
-    'opentech.people',
-    'opentech.search',
-    'opentech.standardpages',
-    'opentech.users',
-    'opentech.utils',
-    'opentech.stream_forms',
+
+    'opentech.apply.categories',
+    'opentech.apply.funds',
+    'opentech.apply.home',
+    'opentech.apply.users',
+    'opentech.apply.stream_forms',
+
+    'opentech.public.esi',
+    'opentech.public.forms',
+    'opentech.public.home',
+    'opentech.public.navigation',
+    'opentech.public.news',
+    'opentech.public.people',
+    'opentech.public.search',
+    'opentech.public.standardpages',
+    'opentech.public.utils',
 
     'wagtail.contrib.modeladmin',
     'wagtail.contrib.postgres_search',
@@ -68,7 +72,7 @@ MIDDLEWARE = [
 
     'wagtail.wagtailcore.middleware.SiteMiddleware',
     'wagtail.wagtailredirects.middleware.RedirectMiddleware',
-    'opentech.esi.middleware.ESIMiddleware',
+    'opentech.public.esi.middleware.ESIMiddleware',
 ]
 
 ROOT_URLCONF = 'opentech.urls'
@@ -87,7 +91,7 @@ TEMPLATES = [
                 'django.contrib.auth.context_processors.auth',
                 'django.contrib.messages.context_processors.messages',
                 'wagtail.contrib.settings.context_processors.settings',
-                'opentech.utils.context_processors.global_vars',
+                'opentech.public.utils.context_processors.global_vars',
             ],
         },
     },
diff --git a/opentech/urls.py b/opentech/urls.py
index 99f5410066ad4a94b25f2b3feaace1ba1f87ca34..f15ca87d8a2f1e85d1753b4bb7f3d778f2348ec7 100644
--- a/opentech/urls.py
+++ b/opentech/urls.py
@@ -10,22 +10,18 @@ from wagtail.wagtailadmin import urls as wagtailadmin_urls
 from wagtail.wagtailcore import urls as wagtail_urls
 from wagtail.wagtaildocs import urls as wagtaildocs_urls
 
+from opentech.public import urls as public_urls
 from opentech.apply import urls as apply_urls
-from opentech.esi import views as esi_views
-from opentech.search import views as search_views
-from opentech.users import urls as users_urls
+
 
 urlpatterns = [
     url(r'^django-admin/', include(admin.site.urls)),
     url(r'^admin/', include(wagtailadmin_urls)),
 
     url(r'^documents/', include(wagtaildocs_urls)),
-    url(r'^search/$', search_views.search, name='search'),
-    url(r'^esi/(.*)/$', esi_views.esi, name='esi'),
     url('^sitemap\.xml$', sitemap),
-
-    url(r'^apply/', include(apply_urls)),
-    url(r'^user/', include(users_urls))
+    url('^', include(public_urls)),
+    url('^', include(apply_urls)),
 ]
 
 
diff --git a/setup.cfg b/setup.cfg
index e96540e05568f7778f04a5bd47be5d3a620860b6..4c681954a8aa3443f634e61c372d56e2260b9d74 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -6,12 +6,12 @@ ignore_missing_imports = True
 ignore_errors = True
 
 # Turn on type checking in the apply folder
-[mypy-opentech.apply.*]
+[mypy-opentech.apply.funds*]
 check_untyped_defs = True
 ignore_errors = False
 
 # Enforce writing type definitions within workflow
-[mypy-opentech.apply.workflow*]
+[mypy-opentech.apply.funds.workflow*]
 disallow_untyped_defs = True
 
 # Exclude migrations globally - must be at end