diff --git a/sage_validation/accounts/__init__.py b/sage_validation/accounts/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/sage_validation/accounts/admin.py b/sage_validation/accounts/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d326a8b63f8a38f65086865388a4cf297515c75
--- /dev/null
+++ b/sage_validation/accounts/admin.py
@@ -0,0 +1,8 @@
+from django.contrib import admin
+from .models import UserActivityLog
+
+@admin.register(UserActivityLog)
+class UserActivityLogAdmin(admin.ModelAdmin):
+    list_display = ("user", "action", "name", "input_file_hash", "output_file_hash", "timestamp")
+    search_fields = ("user__username", "name", "action")
+    list_filter = ("action", "timestamp")
\ No newline at end of file
diff --git a/sage_validation/accounts/apps.py b/sage_validation/accounts/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b8364944a21a590dfae5f68e0930f6754f42afd
--- /dev/null
+++ b/sage_validation/accounts/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class AccountsConfig(AppConfig):
+    default_auto_field = "django.db.models.BigAutoField"
+    name = "sage_validation.accounts"
diff --git a/sage_validation/accounts/migrations/0001_initial.py b/sage_validation/accounts/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..163c095f3f495857b641c7615319b1e8ec05e749
--- /dev/null
+++ b/sage_validation/accounts/migrations/0001_initial.py
@@ -0,0 +1,55 @@
+# Generated by Django 5.0.11 on 2025-03-03 09:09
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    initial = True
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="UserActivityLog",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "action",
+                    models.CharField(
+                        choices=[("upload", "Upload"), ("download", "Download")],
+                        max_length=10,
+                    ),
+                ),
+                ("name", models.CharField(max_length=255)),
+                (
+                    "input_file_hash",
+                    models.CharField(blank=True, max_length=64, null=True),
+                ),
+                (
+                    "output_file_hash",
+                    models.CharField(blank=True, max_length=64, null=True),
+                ),
+                ("timestamp", models.DateTimeField(auto_now_add=True)),
+                (
+                    "user",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="activity_logs",
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+            ],
+        ),
+    ]
diff --git a/sage_validation/accounts/migrations/__init__.py b/sage_validation/accounts/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/sage_validation/accounts/views.py b/sage_validation/accounts/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..91ea44a218fbd2f408430959283f0419c921093e
--- /dev/null
+++ b/sage_validation/accounts/views.py
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
diff --git a/sage_validation/file_validator/views.py b/sage_validation/file_validator/views.py
index bfa80c2cde6e71b61c4849f7183a669d74b739c2..e7c4002a2b40098f0be4fc2040bab3538d2908e4 100644
--- a/sage_validation/file_validator/views.py
+++ b/sage_validation/file_validator/views.py
@@ -11,6 +11,7 @@ from rest_framework.request import Request
 from rest_framework.response import Response
 from rest_framework.views import APIView
 
+from sage_validation.accounts.models import UserActivityLog
 from sage_validation.file_validator.forms import CSVUploadForm
 from sage_validation.file_validator.models import MeoCostCentres, XxData
 
@@ -49,7 +50,15 @@ class CSVUploadAPIView(APIView):
         updated_data = self.update_fields(csv_data)
         request.session["validated_csv"] = updated_data
         request.session.modified = True
-
+        # Log the user activity
+        UserActivityLog.objects.create(
+            user=request.user,
+            action="upload",
+            name=csv_file.name,
+            input_file_hash=UserActivityLog.generate_file_hash(csv_file),
+            output_file_hash=UserActivityLog.generate_file_hash(updated_data),
+            timestamp=timezone.now()
+        )
         return Response({
             "status": "success",
             "message": "File successfully uploaded and processed.",
diff --git a/sage_validation/settings.py b/sage_validation/settings.py
index 353594efe25f8595b1a859dcd76d7c2649c6951c..8e1a0ff1a59f67f2b62dddd01f7dd7442b8d7950 100644
--- a/sage_validation/settings.py
+++ b/sage_validation/settings.py
@@ -36,6 +36,7 @@ INSTALLED_APPS = [
 ]
 LOCAL_APPS = [
     "sage_validation.file_validator",
+    "sage_validation.accounts",
 ]
 THIRD_PARTY_APPS: list[str] = []