diff --git a/opentech/apply/activity/forms.py b/opentech/apply/activity/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..1931ffde3a71848d774ef2b3251679a640e5eea1
--- /dev/null
+++ b/opentech/apply/activity/forms.py
@@ -0,0 +1,9 @@
+from django import forms
+
+from .models import Activity
+
+
+class CommentForm(forms.ModelForm):
+    class Meta:
+        model = Activity
+        fields = ('message',)
diff --git a/opentech/apply/activity/migrations/0001_initial.py b/opentech/apply/activity/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..53a29ded1a2bc878c07217d56acce11f7a4b3c3e
--- /dev/null
+++ b/opentech/apply/activity/migrations/0001_initial.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.8 on 2018-02-28 11:03
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ('funds', '0025_update_with_file_blocks'),
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Activity',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('timestamp', models.DateTimeField(auto_now_add=True)),
+                ('message', models.TextField()),
+                ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='funds.ApplicationSubmission')),
+                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+    ]
diff --git a/opentech/apply/activity/models.py b/opentech/apply/activity/models.py
index 71a836239075aa6e6e4ecb700e9c42c95c022d91..9d47edb7752ff971aa30be17ceb1f1dfe8c86d34 100644
--- a/opentech/apply/activity/models.py
+++ b/opentech/apply/activity/models.py
@@ -1,3 +1,9 @@
+from django.conf import settings
 from django.db import models
 
-# Create your models here.
+
+class Activity(models.Model):
+    timestamp = models.DateTimeField(auto_now_add=True)
+    user = models.ForeignKey(settings.AUTH_USER_MODEL)
+    application = models.ForeignKey('funds.ApplicationSubmission')
+    message = models.TextField()
diff --git a/opentech/apply/activity/views.py b/opentech/apply/activity/views.py
index 91ea44a218fbd2f408430959283f0419c921093e..638e31200cbb6042b4a7f3065240d418b53cd94d 100644
--- a/opentech/apply/activity/views.py
+++ b/opentech/apply/activity/views.py
@@ -1,3 +1,7 @@
-from django.shortcuts import render
+from django.views.generic.edit import ModelFormMixin
 
-# Create your views here.
+from .forms import CommentForm
+
+
+class CommentFormViewMixin(ModelFormMixin):
+    form_class = CommentForm
diff --git a/opentech/apply/funds/views.py b/opentech/apply/funds/views.py
index 6068b7cca4cdf15a0530f7c3cca1a9791ad2134e..076a9db6fd264e8980825695d2c822ebbe75297f 100644
--- a/opentech/apply/funds/views.py
+++ b/opentech/apply/funds/views.py
@@ -5,6 +5,8 @@ from django.views.generic import DetailView
 from django_filters.views import FilterView
 from django_tables2.views import SingleTableMixin
 
+from opentech.apply.activity.views import CommentFormViewMixin
+
 from .models import ApplicationSubmission
 from .tables import SubmissionsTable, SubmissionFilter, SubmissionFilterAndSearch
 from .workflow import SingleStage, DoubleStage
@@ -40,7 +42,7 @@ class SubmissionSearchView(SingleTableMixin, FilterView):
         )
 
 
-class SubmissionDetailView(DetailView):
+class SubmissionDetailView(CommentFormViewMixin, DetailView):
     model = ApplicationSubmission
 
     def get_context_data(self, **kwargs):