diff --git a/.gitignore b/.gitignore
index d97dc8c6b9de7e9ae18108bb63b240fbc55dfc40..26919c55358e695cd19341502743cd68a36f90b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
 venv
 .idea
-*.pyc
\ No newline at end of file
+*.pyc
+/staticfiles/
+.env
\ No newline at end of file
diff --git a/file_validator/forms.py b/file_validator/forms.py
index 835729a22bbbf99596bc904e636928a8b174527e..a5a7b749ff24c774928408ce8a63b66154c7c4a7 100644
--- a/file_validator/forms.py
+++ b/file_validator/forms.py
@@ -1,18 +1,86 @@
-"""Form for uploading CSV files."""
+"""Forms for the file_validator app."""
+import csv
+from collections.abc import Sequence
+from typing import ClassVar
+
 from django import forms
 
 
 class CSVUploadForm(forms.Form):
-    """Form for uploading CSV files."""
+    """Form for uploading CSV files only."""
 
     file = forms.FileField(label="Select a CSV file")
 
+    required_columns: ClassVar[list] = [
+        "AccountNumber", "CBAccountNumber", "DaysDiscountValid", "DiscountValue",
+        "DiscountPercentage", "DueDate", "GoodsValueInAccountCurrency",
+        "PurControlValueInBaseCurrency", "DocumentToBaseCurrencyRate",
+        "DocumentToAccountCurrencyRate", "PostedDate", "QueryCode",
+        "TransactionReference", "SecondReference", "Source",
+        "SYSTraderTranType", "TransactionDate", "UniqueReferenceNumber",
+        "UserNumber", "TaxValue", "SYSTraderGenerationReasonType",
+        "GoodsValueInBaseCurrency"
+    ]
+
+    repeating_columns: ClassVar[dict] = {
+        "NominalAnalysis": [
+            "NominalAnalysisTransactionValue", "NominalAnalysisNominalAccountNumber",
+            "NominalAnalysisNominalCostCentre", "NominalAnalysisNominalDepartment",
+            "NominalAnalysisNominalAnalysisNarrative", "NominalAnalysisTransactionAnalysisCode"
+        ],
+        "TaxAnalysis": [
+            "TaxAnalysisTaxRate", "TaxAnalysisGoodsValueBeforeDiscount",
+            "TaxAnalysisDiscountValue", "TaxAnalysisDiscountPercentage",
+            "TaxAnalysisTaxOnGoodsValue"
+        ]
+    }
+
     def clean_file(self) -> str:
-        """Check if the file is a CSV file."""
+        """Validate the uploaded file format and contents."""
         file = self.cleaned_data["file"]
 
-        # Check if the file is a CSV
         if not file.name.endswith(".csv"):
-            err_msg = "Only CSV files are allowed"
+            err_msg = "File must be in CSV format"
             raise forms.ValidationError(err_msg)
+
+        try:
+            csv_file = file.read().decode("utf-8").splitlines()
+            reader = csv.DictReader(csv_file)
+            fieldnames = reader.fieldnames if reader.fieldnames is not None else []
+
+            missing_columns = [col for col in self.required_columns if col not in fieldnames]
+
+            for section_name, column_list in self.repeating_columns.items():
+                max_repeat = self.get_max_repeat(fieldnames, section_name)
+
+                if max_repeat == 0:
+                    missing_columns.extend([f"{base_col}/1" for base_col in column_list])
+                else:
+                    for repeat in range(1, max_repeat + 1):
+                        missing_columns.extend(
+                            [f"{base_col}/{repeat}" for base_col in column_list if
+                             f"{base_col}/{repeat}" not in fieldnames]
+                        )
+
+            if missing_columns:
+                err_msg = f"Missing required columns: {", ".join(missing_columns)}"
+                raise forms.ValidationError(err_msg)
+
+        except (UnicodeDecodeError, csv.Error) as e:
+            err_msg = f"File could not be processed: {e!s}"
+            raise forms.ValidationError(err_msg) from e
+
         return file
+
+    @staticmethod
+    def get_max_repeat(fieldnames: Sequence[str], section_prefix: str) -> int:
+        """Identify the maximum number of repeats for a section."""
+        max_repeat = 0
+        for field in fieldnames:
+            if field.startswith(section_prefix):
+                try:
+                    repeat_number = int(field.split("/")[-1])
+                    max_repeat = max(max_repeat, repeat_number)
+                except ValueError:
+                    continue
+        return max_repeat
diff --git a/file_validator/templates/upload.html b/file_validator/templates/upload.html
index e6071db188e82aa3482ae50c9379255764bf1790..129121ef05336a83485f0533f17cf4cac7afc749 100644
--- a/file_validator/templates/upload.html
+++ b/file_validator/templates/upload.html
@@ -1,18 +1,22 @@
 {% extends 'base.html' %}
 
-{% block title %}CSV Upload{% endblock %}
+{% block title %}File Upload{% endblock %}
 
 {% block content %}
     <div class="bg-white p-10 rounded-lg shadow-lg w-11/12 md:w-1/2 lg:w-1/3 mx-auto">
-        <h2 class="text-2xl font-bold mb-6 text-gray-800 text-center">Upload CSV</h2>
+        <h2 class="text-2xl font-bold mb-6 text-gray-800 text-center">Upload CSV File</h2>
 
         <form id="uploadForm" enctype="multipart/form-data" class="space-y-6">
             <div>
                 <label for="fileInput" class="block text-sm font-medium text-gray-700 mb-2">Choose CSV File</label>
-                <input type="file" name="file" id="fileInput" accept=".csv" class="w-full border border-gray-300 p-3 rounded-lg focus:outline-none focus:ring focus:ring-blue-400">
+                <input type="file" name="file" id="fileInput" accept=".csv"
+                       class="w-full border border-gray-300 p-3 rounded-lg focus:outline-none focus:ring focus:ring-blue-400">
             </div>
 
-            <button type="submit" class="w-full bg-blue-600 text-white py-3 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring focus:ring-blue-400">Upload</button>
+            <button type="submit"
+                    class="w-full bg-blue-600 text-white py-3 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring focus:ring-blue-400">
+                Upload
+            </button>
         </form>
 
         <!-- Error Display -->
@@ -39,38 +43,56 @@
         form.addEventListener('submit', async function (e) {
             e.preventDefault();
 
-            const formData = new FormData();
-            formData.append('file', fileInput.files[0]);
-
-            const response = await fetch('', {
-                method: 'POST',
-                body: formData,
-                headers: {
-                    'X-CSRFToken': '{{ csrf_token }}',
-                }
-            });
-
-            const result = await response.json();
-
             // Clear previous messages
             errorList.innerHTML = '';
             successMessage.innerHTML = '';
             errorSection.classList.add('hidden');
             successSection.classList.add('hidden');
 
-            if (response.ok && result.status === 'success') {
-                // Show success message
-                successMessage.innerText = result.message;
-                successSection.classList.remove('hidden');
-            } else if (response.status === 400 && result.status === 'error') {
-                // Show errors
-                result.errors.forEach(error => {
-                    const li = document.createElement('li');
-                    li.textContent = error;
-                    errorList.appendChild(li);
+            const formData = new FormData();
+            formData.append('file', fileInput.files[0]);
+
+            try {
+                const response = await fetch('', {
+                    method: 'POST',
+                    body: formData,
+                    headers: {
+                        'X-CSRFToken': '{{ csrf_token }}',
+                    }
                 });
+
+                const result = await response.json();
+
+                if (response.ok && result.status === 'success') {
+                    successMessage.innerText = result.message;
+                    successSection.classList.remove('hidden');
+                } else if (response.status === 400 && result.status === 'error') {
+                    // Handle form errors from the backend
+                    if (Array.isArray(result.errors)) {
+                        result.errors.forEach(errorObj => {
+                            for (const [field, messages] of Object.entries(errorObj)) {
+                                messages.forEach(message => {
+                                    const li = document.createElement('li');
+                                    li.textContent = `${field}: ${message}`;
+                                    errorList.appendChild(li);
+                                });
+                            }
+                        });
+                    } else {
+                        const li = document.createElement('li');
+                        li.textContent = result.errors;
+                        errorList.appendChild(li);
+                    }
+
+                    errorSection.classList.remove('hidden');
+                }
+            } catch (error) {
+                // Handle unexpected errors
+                const li = document.createElement('li');
+                li.textContent = 'An unexpected error occurred. Please try again.';
+                errorList.appendChild(li);
                 errorSection.classList.remove('hidden');
             }
         });
     </script>
-{% endblock %}
+{% endblock %}
\ No newline at end of file
diff --git a/file_validator/views.py b/file_validator/views.py
index 5850fbf4b9ad4dd23132be3bc80e43b6f59bd21b..3dfc3b3d6c6381970aeb6dda325f1124e29bd5cb 100644
--- a/file_validator/views.py
+++ b/file_validator/views.py
@@ -1,13 +1,17 @@
-"""Contains the views for the file_validator app."""
-import csv
-
-from django.http import JsonResponse
+"""Views for the file_validator app."""
+from django.http import HttpRequest, HttpResponse, JsonResponse
+from django.shortcuts import render
 from django.urls import reverse_lazy
 from django.views.generic.edit import FormView
 
 from file_validator.forms import CSVUploadForm
 
 
+def index_view(request: HttpRequest) -> HttpResponse:
+    """Render the index page."""
+    return render(request, "index.html")
+
+
 class CSVUploadView(FormView):
     """View for uploading a CSV file."""
 
@@ -18,40 +22,14 @@ class CSVUploadView(FormView):
     def get_context_data(self, **kwargs: dict) -> dict:
         """Render the form with no error message on GET request."""
         context = super().get_context_data(**kwargs)
-        context["error"] = None  # No error message on GET request
-        context["message"] = None  # No success message on GET request
+        context["error"] = None
+        context["message"] = None
         return context
 
-    def form_valid(self, form: CSVUploadForm) -> JsonResponse:
-        """Handle the CSV validation and passes appropriate error or success messages to the template."""
-        file_obj = form.cleaned_data["file"]
-
-        try:
-            # Read and decode the CSV file
-            csv_file = file_obj.read().decode("utf-8").splitlines()
-            reader = csv.DictReader(csv_file)
-
-            # Example validation: Check for required columns
-            # TODO: Add the validation logic here. This is just a sample.
-            required_columns = ["name"]
-            fieldnames = reader.fieldnames if reader.fieldnames is not None else []
-            missing_columns = [col for col in required_columns if col not in fieldnames]
-
-            if missing_columns:
-                # If there are missing columns, return error message as JSON
-                return JsonResponse(
-                    {"status": "error", "errors": [f"Missing columns: {", ".join(missing_columns)}"]}, status=400
-                )
-
-            return JsonResponse({"status": "success", "message": "CSV file is valid"})
-
-        except (UnicodeDecodeError, csv.Error) as e:
-            # If there"s an error (e.g., invalid file content), return the error message as JSON
-            return JsonResponse({"status": "error", "errors": [str(e)]}, status=400)
+    def form_valid(self, form: CSVUploadForm) -> JsonResponse:  # noqa: ARG002
+        """Handle the CSV validation and passes appropriate success messages to the template."""
+        return JsonResponse({"status": "success", "message": "File is valid"})
 
     def form_invalid(self, form: CSVUploadForm) -> JsonResponse:
-        """Handle the form when it is invalid (e.g., wrong file type).
-
-        It renders the form again with errors.
-        """
+        """Handle the form when it is invalid (e.g., wrong file type or validation errors)."""
         return JsonResponse({"status": "error", "errors": [form.errors]}, status=400)
diff --git a/manage.py b/manage.py
index e2e965b011fa11939aeaf148c6e17e0400022cd6..67ea5e4cbb8202597343ffe6a5bc51059d36856e 100755
--- a/manage.py
+++ b/manage.py
@@ -6,7 +6,7 @@ import sys
 
 def main():
     """Run administrative tasks."""
-    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'root.settings')
     try:
         from django.core.management import execute_from_command_line
     except ImportError as exc:
diff --git a/root/asgi.py b/root/asgi.py
index c485c36537c18a1c772e5aaec678d8cbafcfca42..eccdd2b9f696ed00332f24fb18cb466ab4e2a5c8 100644
--- a/root/asgi.py
+++ b/root/asgi.py
@@ -1,12 +1,10 @@
-"""
-ASGI config for sage_validation project.
+"""ASGI config for sage_validation project.
 
 It exposes the ASGI callable as a module-level variable named ``application``.
 
 For more information on this file, see
 https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
 """
-
 import os
 
 from django.core.asgi import get_asgi_application
diff --git a/root/settings.py b/root/settings.py
index d3dae657012bad907a1c3928b94fc0f59e6e5f79..41c166d2b163fe81b1df9ef796dcd26c5ee5061d 100644
--- a/root/settings.py
+++ b/root/settings.py
@@ -1,5 +1,4 @@
-"""
-Django settings for sage_validation project.
+"""Django settings for sage_validation project.
 
 Generated by 'django-admin startproject' using Django 5.1.1.
 
@@ -9,7 +8,7 @@ https://docs.djangoproject.com/en/5.1/topics/settings/
 For the full list of settings and their values, see
 https://docs.djangoproject.com/en/5.1/ref/settings/
 """
-
+import os
 from pathlib import Path
 
 # Build paths inside the project like this: BASE_DIR / 'subdir'.
@@ -19,7 +18,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
 # See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
 
 # SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = "django-insecure-9tdba&yktxzclzokj^=uxfsmisgeo8(6!p3koa8ndy8s^3x@@y"
+SECRET_KEY = os.getenv("SECRET_KEY")
 
 # SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = True
@@ -60,7 +59,7 @@ ROOT_URLCONF = "root.urls"
 TEMPLATES = [
     {
         "BACKEND": "django.template.backends.django.DjangoTemplates",
-        "DIRS": [BASE_DIR / 'templates'],
+        "DIRS": [BASE_DIR / "templates"],
         "APP_DIRS": True,
         "OPTIONS": {
             "context_processors": [
@@ -127,3 +126,8 @@ INTERNAL_IPS = [
     "127.0.0.1",
 ]
 TAILWIND_APP_NAME = "theme"
+
+STATIC_ROOT = BASE_DIR / "staticfiles"
+STATICFILES_DIRS = [
+    BASE_DIR / "static",
+]
diff --git a/root/wsgi.py b/root/wsgi.py
index 31800a890134111a1cee0602c7af43bfa2d86272..095478e2e85f90e0b0b4807d8c49377104deb354 100644
--- a/root/wsgi.py
+++ b/root/wsgi.py
@@ -1,5 +1,4 @@
-"""
-WSGI config for sage_validation project.
+"""WSGI config for sage_validation project.
 
 It exposes the WSGI callable as a module-level variable named ``application``.